├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable │ │ │ │ ├── ic_person_black_24dp.xml │ │ │ │ ├── ic_launcher_foreground.xml │ │ │ │ └── ic_launcher_background.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── layout │ │ │ │ └── activity_main.xml │ │ ├── ic_launcher-web.png │ │ ├── java │ │ │ └── com │ │ │ │ └── redmadrobot │ │ │ │ └── acronymavatarsample │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── redmadrobot │ │ │ └── acronymavatarsample │ │ │ └── ExampleUnitTest.kt │ └── androidTest │ │ └── java │ │ └── com │ │ └── redmadrobot │ │ └── acronymavatarsample │ │ └── ExampleInstrumentedTest.kt ├── proguard-rules.pro └── build.gradle.kts ├── acronymavatar ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ ├── values │ │ │ ├── attrs.xml │ │ │ └── default_colors.xml │ │ └── drawable │ │ │ └── default_placeholder.xml │ │ └── kotlin │ │ └── com │ │ └── redmadrobot │ │ └── acronymavatar │ │ ├── AcronymDrawable.kt │ │ └── AvatarView.kt ├── library.properties ├── proguard-rules.pro └── build.gradle.kts ├── settings.gradle.kts ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── publish.gradle ├── detekt ├── detekt-baseline.xml └── config.yml ├── gradle.properties ├── LICENSE ├── gradlew.bat ├── .gitignore ├── README.MD └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /acronymavatar/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /acronymavatar/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | include (":acronymavatar") 2 | include (":app") 3 | rootProject.name = "AcronymAvatar" 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Sample 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedMadRobot/acronym-avatar/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /detekt/detekt-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /acronymavatar/library.properties: -------------------------------------------------------------------------------- 1 | lib_name=acronymavatar 2 | lib_description=Library to show avatars with acronyms. 3 | lib_vcs=https://github.com/RedMadRobot/acronym-avatar.git 4 | lib_issue_tracker=https://github.com/RedMadRobot/acronym-avatar/issues 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /acronymavatar/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/test/java/com/redmadrobot/acronymavatarsample/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.redmadrobot.acronymavatarsample 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/redmadrobot/acronymavatarsample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.redmadrobot.acronymavatarsample 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import kotlinx.android.synthetic.main.activity_main.* 6 | 7 | class MainActivity : AppCompatActivity() { 8 | 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | setContentView(R.layout.activity_main) 12 | 13 | dynamic_avatar.setText("User Avatar") 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/redmadrobot/acronymavatarsample/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.redmadrobot.acronymavatarsample 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.test.runner.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getTargetContext() 22 | assertEquals("com.redmadrobot.acronymavatarsample", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /acronymavatar/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle.kts. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | android.enableJetifier=true 10 | android.useAndroidX=true 11 | org.gradle.jvmargs=-Xmx2048m 12 | kotlin.code.style=official 13 | # When configured, Gradle will run in incubating parallel mode. 14 | # This option should only be used with decoupled projects. More details, visit 15 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 16 | # org.gradle.parallel=true 17 | -------------------------------------------------------------------------------- /acronymavatar/src/main/res/values/default_colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #436ecd 4 | #21ac94 5 | #29ae5c 6 | #a6c706 7 | #ff7308 8 | #ff7307 9 | #f0592f 10 | #cd4b7d 11 | #9d5cb3 12 | #675cb3 13 | 14 | 15 | @color/leo 16 | @color/nadja 17 | @color/mark 18 | @color/teresa 19 | @color/georgina 20 | @color/lucia 21 | @color/jelena 22 | @color/liby 23 | @color/tibor 24 | @color/sergio 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Redmadrobot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id(Android.applicationPlugin) 3 | 4 | kotlin(Kotlin.androidPlugin) 5 | kotlin(Kotlin.androidExtensions) 6 | } 7 | 8 | android { 9 | compileSdkVersion(Android.compileSdk) 10 | buildToolsVersion(Android.buildTools) 11 | 12 | defaultConfig { 13 | applicationId = Android.DefaultConfig.applicationId 14 | 15 | minSdkVersion(Android.DefaultConfig.minSdk) 16 | targetSdkVersion(Android.DefaultConfig.targetSdk) 17 | 18 | versionCode = Android.DefaultConfig.versionCode 19 | versionName = Android.DefaultConfig.versionName 20 | 21 | testInstrumentationRunner = Android.DefaultConfig.instrumentationRunner 22 | 23 | 24 | buildTypes { 25 | getByName(Android.BuildTypes.release) { 26 | isMinifyEnabled = false 27 | 28 | proguardFiles( 29 | getDefaultProguardFile(Android.Proguard.androidOptimizedRules), 30 | Android.Proguard.projectRules 31 | ) 32 | } 33 | } 34 | 35 | compileOptions { 36 | sourceCompatibility = JavaVersion.VERSION_1_8 37 | targetCompatibility = JavaVersion.VERSION_1_8 38 | } 39 | 40 | kotlinOptions { 41 | jvmTarget = "1.8" 42 | } 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation(project(":acronymavatar")) 48 | 49 | implementation(Kotlin.stdLib) 50 | implementation(Dependencies.Common.appCompat) 51 | implementation(Dependencies.App.constraintlayout) 52 | } 53 | -------------------------------------------------------------------------------- /acronymavatar/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id(Android.libraryPlugin) 3 | kotlin(Kotlin.androidPlugin) 4 | kotlin(Kotlin.androidExtensions) 5 | } 6 | apply(from = "../gradle/publish.gradle") 7 | 8 | android { 9 | compileSdkVersion(Android.compileSdk) 10 | 11 | defaultConfig { 12 | minSdkVersion(Android.DefaultConfig.minSdk) 13 | targetSdkVersion(Android.DefaultConfig.targetSdk) 14 | versionCode = Android.DefaultConfig.versionCode 15 | versionName = Android.DefaultConfig.versionName 16 | 17 | testInstrumentationRunner = Android.DefaultConfig.instrumentationRunner 18 | 19 | consumerProguardFile("consumer-rules.pro") 20 | } 21 | 22 | testOptions { 23 | unitTests.isReturnDefaultValues = true 24 | } 25 | 26 | buildTypes { 27 | getByName(Android.BuildTypes.release) { 28 | isMinifyEnabled = false 29 | proguardFiles( 30 | getDefaultProguardFile(Android.Proguard.androidOptimizedRules), 31 | Android.Proguard.projectRules 32 | ) 33 | } 34 | } 35 | 36 | compileOptions { 37 | sourceCompatibility = JavaVersion.VERSION_1_8 38 | targetCompatibility = JavaVersion.VERSION_1_8 39 | } 40 | 41 | kotlinOptions { 42 | jvmTarget = "1.8" 43 | } 44 | 45 | for (sourceSet in sourceSets) { 46 | sourceSet.java.srcDirs("src/${sourceSet.name}/kotlin") 47 | } 48 | 49 | packagingOptions { 50 | exclude("META-INF/LICENSE*") 51 | } 52 | } 53 | 54 | dependencies { 55 | implementation(Kotlin.stdLib) 56 | implementation(Dependencies.Common.appCompat) 57 | } 58 | -------------------------------------------------------------------------------- /acronymavatar/src/main/kotlin/com/redmadrobot/acronymavatar/AcronymDrawable.kt: -------------------------------------------------------------------------------- 1 | package com.redmadrobot.acronymavatar 2 | 3 | import android.graphics.* 4 | import android.graphics.drawable.Drawable 5 | import kotlin.math.min 6 | 7 | 8 | class AcronymDrawable(private val acronym: String, backgroundColor: Int, private val sizeFactor: Float) : Drawable() { 9 | 10 | private val paintBackground = Paint(Paint.ANTI_ALIAS_FLAG) 11 | private val paintText = Paint(Paint.ANTI_ALIAS_FLAG) 12 | 13 | private val boundsRect = RectF() 14 | 15 | init { 16 | setColors(backgroundColor) 17 | } 18 | 19 | override fun draw(canvas: Canvas) { 20 | boundsRect.set(bounds) 21 | 22 | paintText.textSize = bounds.height() / sizeFactor 23 | 24 | val radius = min(boundsRect.width(), boundsRect.height()) / 2 25 | canvas.drawCircle(boundsRect.centerX(), boundsRect.centerY(), radius, paintBackground) 26 | 27 | val yTextPosition = boundsRect.centerY() - paintText.ascent() / 2 - paintText.descent() / 2 28 | canvas.drawText(acronym, boundsRect.centerX(), yTextPosition, paintText) 29 | } 30 | 31 | override fun setAlpha(alpha: Int) { 32 | paintText.alpha = alpha 33 | paintBackground.alpha = alpha 34 | } 35 | 36 | override fun getOpacity() = PixelFormat.UNKNOWN 37 | 38 | override fun setColorFilter(colorFilter: ColorFilter?) { 39 | /* Not used */ 40 | } 41 | 42 | private fun setColors(backgroundColor: Int, textColor: Int = 0xFFFFFFFF.toInt()) { 43 | paintBackground.color = backgroundColor 44 | 45 | with(paintText) { 46 | color = textColor 47 | textAlign = Paint.Align.CENTER 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /gradle/publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "maven-publish" 2 | apply plugin: "com.jfrog.bintray" 3 | 4 | def publishPropertiesFile = rootProject.file("gradle/publish.properties") 5 | def publishProperties = new Properties() 6 | 7 | if (publishPropertiesFile.canRead()) { 8 | publishProperties.load(new FileInputStream(publishPropertiesFile)) 9 | } 10 | 11 | def libraryPropertiesFile = file("library.properties") 12 | def libraryProperties = new Properties() 13 | 14 | if (libraryPropertiesFile.canRead()) { 15 | libraryProperties.load(new FileInputStream(libraryPropertiesFile)) 16 | } 17 | 18 | task androidSourcesJar(type: Jar) { 19 | archiveClassifier.set('sources') 20 | from android.sourceSets.main.java.srcDirs 21 | } 22 | 23 | afterEvaluate { 24 | publishing { 25 | publications { 26 | release(MavenPublication) { 27 | from components.release 28 | 29 | artifact androidSourcesJar 30 | 31 | groupId = publishProperties["group_id"] 32 | artifactId = libraryProperties["lib_name"] 33 | version = publishProperties["lib_version"] 34 | } 35 | } 36 | repositories { 37 | maven { 38 | name = "GitHubPackages" 39 | 40 | url = uri("https://maven.pkg.github.com/RedMadRobot/acronym-avatar") 41 | credentials { 42 | username = System.getenv("GITHUB_USER") 43 | password = System.getenv("GITHUB_TOKEN") 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | bintray { 51 | user = System.getenv("BINTRAY_USER") 52 | key = System.getenv("BINTRAY_KEY") 53 | publications = ["release"] 54 | override = true 55 | 56 | pkg { 57 | repo = publishProperties["repository"] 58 | name = libraryProperties["lib_name"] 59 | description = libraryProperties["lib_description"] 60 | userOrg = publishProperties["organization_id"] 61 | licenses = ["MIT"] 62 | vcsUrl = libraryProperties["lib_vcs"] 63 | issueTrackerUrl = libraryProperties["lib_issue_tracker"] 64 | publish = true 65 | publicDownloadNumbers = true 66 | 67 | version { 68 | name = publishProperties["lib_version"] 69 | released = new Date() 70 | vcsTag = publishProperties["lib_version"] 71 | } 72 | 73 | dryRun = false 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | ### Android template 12 | # Built application files 13 | *.apk 14 | *.ap_ 15 | 16 | # Files for the ART/Dalvik VM 17 | *.dex 18 | 19 | # Java class files 20 | *.class 21 | 22 | # Generated files 23 | bin/ 24 | gen/ 25 | out/ 26 | 27 | # Gradle files 28 | .gradle/ 29 | build/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Proguard folder generated by Eclipse 35 | proguard/ 36 | 37 | # Log Files 38 | *.log 39 | 40 | # Android Studio Navigation editor temp files 41 | .navigation/ 42 | 43 | # Android Studio captures folder 44 | captures/ 45 | 46 | # IntelliJ 47 | .idea/ 48 | 49 | # Keystore files 50 | # Uncomment the following line if you do not want to check your keystore files in. 51 | #*.jks 52 | 53 | # External native build folder generated in Android Studio 2.2 and later 54 | 55 | # Google Services (e.g. APIs or Firebase) 56 | google-services.json 57 | 58 | # Freeline 59 | freeline.py 60 | freeline/ 61 | freeline_project_description.json 62 | 63 | # fastlane 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | fastlane/readme.md 69 | ### JetBrains template 70 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 71 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 72 | 73 | # User-specific stuff: 74 | .idea/**/workspace.xml 75 | .idea/**/tasks.xml 76 | 77 | # Sensitive or high-churn files: 78 | .idea/**/dataSources/ 79 | .idea/**/dataSources.ids 80 | .idea/**/dataSources.local.xml 81 | .idea/**/sqlDataSources.xml 82 | .idea/**/dynamic.xml 83 | .idea/**/uiDesigner.xml 84 | 85 | # Gradle: 86 | .idea/**/gradle.xml 87 | .idea/**/libraries 88 | 89 | # CMake 90 | cmake-build-debug/ 91 | cmake-build-release/ 92 | 93 | # Mongo Explorer plugin: 94 | .idea/**/mongoSettings.xml 95 | 96 | ## File-based project format: 97 | *.iws 98 | 99 | ## Plugin-specific files: 100 | 101 | # IntelliJ 102 | 103 | # mpeltonen/sbt-idea plugin 104 | .idea_modules/ 105 | 106 | # JIRA plugin 107 | atlassian-ide-plugin.xml 108 | 109 | # Cursive Clojure plugin 110 | .idea/replstate.xml 111 | 112 | # Crashlytics plugin (for Android Studio and IntelliJ) 113 | com_crashlytics_export_strings.xml 114 | crashlytics.properties 115 | crashlytics-build.properties 116 | fabric.properties 117 | 118 | gradle/publish.properties -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | Logo 2 | 3 | [![Bintray](https://api.bintray.com/packages/redmadrobot-opensource/android/acronym-avatar/images/download.svg)](https://bintray.com/redmadrobot-opensource/android/acronym-avatar/_latestVersion) 4 | 5 | # Description 6 | 7 | AcronymAvatar is a dumb simple library to show avatars with acronyms in your application. Should you like to show user's list in your messenger (yet another one...) or just create an unorthodox user profile? This library is the best choice for you. 8 | 9 | UI sample 10 | 11 | # Getting started 12 | 13 | Just include the library into your project as a Gradle dependency: 14 | ```Groovy 15 | implementation 'com.redmadrobot:acronym-avatar:2.0' 16 | ``` 17 | 18 | Then add `AvatarView` into your XML layout: 19 | ```XML 20 | 24 | ``` 25 | 26 | And pass full username to the `setText` method: 27 | ```Kotlin 28 | user_avatar.setText("Captain Nemo") 29 | ``` 30 | 31 | That's all! 32 | 33 | 34 | # Capabilities 35 | 36 | * Setting text via XML and programmatically 37 | * Using custom placeholders (Drawables only!) 38 | * Configuring zoom out for the acronym 39 | 40 | ## Setting text via XML and programmatically 41 | Composing acronyms from text works like this: when you pass a single word through the `setText` method or through the `app:text` XML field, the library takes only first two symbols, and makes them an uppercased acronym. In case there are two or more words, the library takes first symbols from first and second words only, and makes them an uppercased acronym. For instance: 42 | * Captain -> CA 43 | * Captain Nemo -> CN 44 | * Nemo, my name forever more -> NM 45 | 46 | ## Using custom placeholders (Drawables only!) 47 | We like our default placeholder very much, but you won't probably want to use it in real-world applications ;) For this case we augmented our library with a custom placeholder feature. You can set it via XML as following: 48 | ```XML 49 | 54 | ``` 55 | 56 | ## Configuring zoom out for the acronym 57 | The library is preconfigured to use optimal text zoom factor, but you can set your own value this way: 58 | ```XML 59 | 64 | ``` 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 29 | 30 | 38 | 39 | 50 | 51 | 62 | 63 | 75 | 76 | -------------------------------------------------------------------------------- /acronymavatar/src/main/kotlin/com/redmadrobot/acronymavatar/AvatarView.kt: -------------------------------------------------------------------------------- 1 | package com.redmadrobot.acronymavatar 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.drawable.Drawable 6 | import android.util.AttributeSet 7 | import android.util.DisplayMetrics 8 | import androidx.appcompat.widget.AppCompatImageView 9 | import androidx.core.content.ContextCompat 10 | import kotlin.properties.Delegates 11 | 12 | 13 | class AvatarView : AppCompatImageView { 14 | companion object { 15 | private const val DEFAULT_ZOOM_OUT = 2.3f 16 | private const val DEFAULT_WIDTH_DP = 40 17 | private const val DEFAULT_HEIGHT_DP = 40 18 | } 19 | 20 | private var rawText by Delegates.notNull() 21 | private var placeholder by Delegates.notNull() 22 | private var zoomOut by Delegates.notNull() 23 | 24 | private val colors = context.resources.getIntArray(R.array.avatar_colors_set) 25 | 26 | private val wordRegex = Regex("([a-zа-я]+)", RegexOption.IGNORE_CASE) 27 | 28 | constructor(context: Context) : super(context) { 29 | initView() 30 | } 31 | 32 | @JvmOverloads 33 | constructor(context: Context, attrs: AttributeSet, defStyle: Int = 0) : super(context, attrs, defStyle) { 34 | val additionalAttrs = context.obtainStyledAttributes(attrs, R.styleable.AvatarView, defStyle, 0) 35 | 36 | rawText = additionalAttrs.getString(R.styleable.AvatarView_text) ?: "" 37 | placeholder = additionalAttrs.getDrawable(R.styleable.AvatarView_placeholder) ?: getDefaultPlaceholder()!! 38 | zoomOut = additionalAttrs.getFloat(R.styleable.AvatarView_zoom_out, DEFAULT_ZOOM_OUT) 39 | 40 | additionalAttrs.recycle() 41 | 42 | initView() 43 | } 44 | 45 | override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { 46 | setMeasuredDimension(calculateWidth(widthMeasureSpec), calculateHeight(heightMeasureSpec)) 47 | } 48 | 49 | fun setText(value: String) { 50 | rawText = value 51 | initView() 52 | } 53 | 54 | private fun initView() { 55 | if (rawText.isEmpty() || wordRegex.findAll(rawText).count() == 0) { 56 | setImageDrawable(placeholder) 57 | } else { 58 | val acronym = getAcronym(rawText) 59 | val backgroundColor = colors[Math.abs(rawText.hashCode() % colors.size)] 60 | 61 | setImageDrawable(AcronymDrawable(acronym, backgroundColor, zoomOut)) 62 | } 63 | } 64 | 65 | private fun getAcronym(text: String): String { 66 | val words = wordRegex.findAll(text) 67 | 68 | return when (words.count()) { 69 | 0 -> "" 70 | 1 -> words.first().value.take(2) 71 | else -> words.take(2).map { it.value.take(1) }.reduce { s1, s2 -> "$s1$s2" } 72 | }.toUpperCase() 73 | } 74 | 75 | private fun getDefaultPlaceholder() = ContextCompat.getDrawable(context, R.drawable.default_placeholder) 76 | 77 | private fun calculateWidth(widthMeasureSpec: Int) = getMeasurment(widthMeasureSpec, dp2px(DEFAULT_WIDTH_DP)) 78 | private fun calculateHeight(heightMeasureSpec: Int) = getMeasurment(heightMeasureSpec, dp2px(DEFAULT_HEIGHT_DP)) 79 | 80 | @SuppressLint("SwitchIntDef") 81 | private fun getMeasurment(measureSpec: Int, defaultSize: Int): Int { 82 | val specSize = MeasureSpec.getSize(measureSpec) 83 | 84 | return when(MeasureSpec.getMode(measureSpec)) { 85 | MeasureSpec.EXACTLY -> specSize 86 | else -> defaultSize 87 | } 88 | } 89 | 90 | private fun dp2px(dp: Int) = dp * (resources.displayMetrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT) 91 | } 92 | -------------------------------------------------------------------------------- /acronymavatar/src/main/res/drawable/default_placeholder.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | 72 | 78 | 84 | 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 14 | 20 | 26 | 32 | 38 | 44 | 50 | 56 | 62 | 68 | 74 | 80 | 86 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /detekt/config.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 0 3 | excludeCorrectable: false 4 | weights: 5 | complexity: 2 6 | formatting: 1 7 | style: 1 8 | comments: 0.5 9 | 10 | config: 11 | validation: true 12 | # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' 13 | excludes: '' 14 | 15 | processors: 16 | active: true 17 | exclude: 18 | - 'DetektProgressListener' 19 | # - 'FunctionCountProcessor' 20 | # - 'PropertyCountProcessor' 21 | # - 'ClassCountProcessor' 22 | # - 'PackageCountProcessor' 23 | # - 'KtFileCountProcessor' 24 | 25 | console-reports: 26 | active: true 27 | exclude: 28 | - 'ProjectStatisticsReport' 29 | - 'ComplexityReport' 30 | - 'NotificationReport' 31 | # - 'FindingsReport' 32 | - 'FileBasedFindingsReport' 33 | 34 | comments: 35 | active: true 36 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 37 | AbsentOrWrongFileLicense: 38 | active: false 39 | licenseTemplateFile: 'license.template' 40 | CommentOverPrivateFunction: 41 | active: false 42 | CommentOverPrivateProperty: 43 | active: false 44 | EndOfSentenceFormat: 45 | active: false 46 | endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' 47 | UndocumentedPublicClass: 48 | active: false 49 | searchInNestedClass: true 50 | searchInInnerClass: true 51 | searchInInnerObject: true 52 | searchInInnerInterface: true 53 | UndocumentedPublicFunction: 54 | active: false 55 | UndocumentedPublicProperty: 56 | active: false 57 | 58 | complexity: 59 | active: true 60 | ComplexCondition: 61 | active: true 62 | threshold: 4 63 | ComplexInterface: 64 | active: false 65 | threshold: 10 66 | includeStaticDeclarations: false 67 | includePrivateDeclarations: false 68 | ComplexMethod: 69 | active: true 70 | threshold: 10 71 | ignoreSingleWhenExpression: false 72 | ignoreSimpleWhenEntries: false 73 | ignoreNestingFunctions: false 74 | nestingFunctions: [run, let, apply, with, also, use, forEach, isNotNull, ifNull] 75 | LabeledExpression: 76 | active: false 77 | ignoredLabels: [] 78 | LargeClass: 79 | active: true 80 | threshold: 600 81 | LongMethod: 82 | active: true 83 | threshold: 60 84 | LongParameterList: 85 | active: true 86 | functionThreshold: 6 87 | constructorThreshold: 12 88 | ignoreDefaultParameters: true 89 | ignoreDataClasses: true 90 | ignoreAnnotated: [JsonClass] 91 | MethodOverloading: 92 | active: false 93 | threshold: 6 94 | NestedBlockDepth: 95 | active: true 96 | threshold: 4 97 | StringLiteralDuplication: 98 | active: true 99 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 100 | threshold: 3 101 | ignoreAnnotation: true 102 | excludeStringsWithLessThan5Characters: true 103 | ignoreStringsRegex: '$^' 104 | TooManyFunctions: 105 | active: true 106 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 107 | thresholdInFiles: 20 108 | thresholdInClasses: 20 109 | thresholdInInterfaces: 20 110 | thresholdInObjects: 20 111 | thresholdInEnums: 20 112 | ignoreDeprecated: false 113 | ignorePrivate: false 114 | ignoreOverridden: true 115 | 116 | coroutines: 117 | active: false 118 | GlobalCoroutineUsage: 119 | active: false 120 | RedundantSuspendModifier: 121 | active: false 122 | 123 | empty-blocks: 124 | active: true 125 | EmptyCatchBlock: 126 | active: true 127 | allowedExceptionNameRegex: '_|(ignore|expected).*' 128 | EmptyClassBlock: 129 | active: true 130 | EmptyDefaultConstructor: 131 | active: true 132 | EmptyDoWhileBlock: 133 | active: true 134 | EmptyElseBlock: 135 | active: true 136 | EmptyFinallyBlock: 137 | active: true 138 | EmptyForBlock: 139 | active: true 140 | EmptyFunctionBlock: 141 | active: true 142 | ignoreOverridden: false 143 | EmptyIfBlock: 144 | active: true 145 | EmptyInitBlock: 146 | active: true 147 | EmptyKtFile: 148 | active: true 149 | EmptySecondaryConstructor: 150 | active: true 151 | EmptyTryBlock: 152 | active: true 153 | EmptyWhenBlock: 154 | active: true 155 | EmptyWhileBlock: 156 | active: true 157 | 158 | exceptions: 159 | active: true 160 | ExceptionRaisedInUnexpectedLocation: 161 | active: true 162 | methodNames: [toString, hashCode, equals, finalize] 163 | InstanceOfCheckForException: 164 | active: true 165 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 166 | NotImplementedDeclaration: 167 | active: true 168 | PrintStackTrace: 169 | active: true 170 | RethrowCaughtException: 171 | active: true 172 | ReturnFromFinally: 173 | active: true 174 | ignoreLabeled: false 175 | SwallowedException: 176 | active: true 177 | ignoredExceptionTypes: 178 | - InterruptedException 179 | - NumberFormatException 180 | - ParseException 181 | - MalformedURLException 182 | allowedExceptionNameRegex: '_|(ignore|expected).*' 183 | ThrowingExceptionFromFinally: 184 | active: false 185 | ThrowingExceptionInMain: 186 | active: false 187 | ThrowingExceptionsWithoutMessageOrCause: 188 | active: true 189 | exceptions: 190 | - IllegalArgumentException 191 | - IllegalStateException 192 | - IOException' 193 | ThrowingNewInstanceOfSameException: 194 | active: false 195 | TooGenericExceptionCaught: 196 | active: true 197 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 198 | exceptionNames: 199 | - ArrayIndexOutOfBoundsException 200 | - Error 201 | - Exception 202 | - IllegalMonitorStateException 203 | - NullPointerException 204 | - IndexOutOfBoundsException 205 | - RuntimeException 206 | - Throwable 207 | allowedExceptionNameRegex: '_|(ignore|expected).*' 208 | TooGenericExceptionThrown: 209 | active: true 210 | exceptionNames: 211 | - Error 212 | - Exception 213 | - Throwable 214 | - RuntimeException 215 | 216 | formatting: 217 | active: true 218 | android: true 219 | autoCorrect: true 220 | AnnotationOnSeparateLine: 221 | active: false 222 | autoCorrect: true 223 | ChainWrapping: 224 | active: true 225 | autoCorrect: true 226 | CommentSpacing: 227 | active: true 228 | autoCorrect: true 229 | EnumEntryNameCase: 230 | active: false 231 | autoCorrect: true 232 | Filename: 233 | active: true 234 | FinalNewline: 235 | active: true 236 | autoCorrect: true 237 | insertFinalNewLine: true 238 | ImportOrdering: 239 | active: false 240 | autoCorrect: true 241 | Indentation: 242 | active: true 243 | autoCorrect: true 244 | indentSize: 4 245 | continuationIndentSize: 4 246 | MaximumLineLength: 247 | active: false # See style.MaxLineLength 248 | maxLineLength: 120 249 | ModifierOrdering: 250 | active: true 251 | autoCorrect: true 252 | MultiLineIfElse: 253 | active: true 254 | autoCorrect: true 255 | NoBlankLineBeforeRbrace: 256 | active: false 257 | autoCorrect: false 258 | NoConsecutiveBlankLines: 259 | active: true 260 | autoCorrect: true 261 | NoEmptyClassBody: 262 | active: true 263 | autoCorrect: true 264 | NoEmptyFirstLineInMethodBlock: 265 | active: false 266 | autoCorrect: true 267 | NoLineBreakAfterElse: 268 | active: true 269 | autoCorrect: true 270 | NoLineBreakBeforeAssignment: 271 | active: true 272 | autoCorrect: true 273 | NoMultipleSpaces: 274 | active: true 275 | autoCorrect: true 276 | NoSemicolons: 277 | active: true 278 | autoCorrect: true 279 | NoTrailingSpaces: 280 | active: true 281 | autoCorrect: true 282 | NoUnitReturn: 283 | active: true 284 | autoCorrect: true 285 | NoUnusedImports: 286 | active: true 287 | autoCorrect: true 288 | NoWildcardImports: 289 | active: false 290 | PackageName: 291 | active: false 292 | autoCorrect: true 293 | ParameterListWrapping: 294 | active: true 295 | autoCorrect: true 296 | indentSize: 4 297 | SpacingAroundColon: 298 | active: true 299 | autoCorrect: true 300 | SpacingAroundComma: 301 | active: true 302 | autoCorrect: true 303 | SpacingAroundCurly: 304 | active: true 305 | autoCorrect: true 306 | SpacingAroundDot: 307 | active: true 308 | autoCorrect: true 309 | SpacingAroundKeyword: 310 | active: true 311 | autoCorrect: true 312 | SpacingAroundOperators: 313 | active: true 314 | autoCorrect: true 315 | SpacingAroundParens: 316 | active: true 317 | autoCorrect: true 318 | SpacingAroundRangeOperator: 319 | active: true 320 | autoCorrect: true 321 | StringTemplate: 322 | active: true 323 | autoCorrect: true 324 | 325 | naming: 326 | active: true 327 | ClassNaming: 328 | active: true 329 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 330 | classPattern: '[A-Z][a-zA-Z0-9]*' 331 | ConstructorParameterNaming: 332 | active: true 333 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 334 | parameterPattern: '[a-z][A-Za-z0-9]*' 335 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 336 | excludeClassPattern: '$^' 337 | ignoreOverridden: true 338 | EnumNaming: 339 | active: true 340 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 341 | enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' 342 | ForbiddenClassName: 343 | active: false 344 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 345 | forbiddenName: [] 346 | FunctionMaxLength: 347 | active: false 348 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 349 | maximumFunctionNameLength: 30 350 | FunctionMinLength: 351 | active: false 352 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 353 | minimumFunctionNameLength: 3 354 | FunctionNaming: 355 | active: true 356 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 357 | functionPattern: '([a-z][a-zA-Z0-9]*)|(`.*`)' 358 | excludeClassPattern: '$^' 359 | ignoreOverridden: true 360 | FunctionParameterNaming: 361 | active: true 362 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 363 | parameterPattern: '[a-z][A-Za-z0-9]*' 364 | excludeClassPattern: '$^' 365 | ignoreOverridden: true 366 | InvalidPackageDeclaration: 367 | active: false 368 | rootPackage: '' 369 | MatchingDeclarationName: 370 | active: true 371 | mustBeFirst: true 372 | MemberNameEqualsClassName: 373 | active: true 374 | ignoreOverridden: true 375 | ObjectPropertyNaming: 376 | active: true 377 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 378 | constantPattern: '[A-Za-z][_A-Za-z0-9]*' 379 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 380 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' 381 | PackageNaming: 382 | active: true 383 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 384 | packagePattern: '[a-z][_a-z0-9]*(\.[a-z][_a-z0-9]*)*' 385 | TopLevelPropertyNaming: 386 | active: true 387 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 388 | constantPattern: '[A-Z][_A-Z0-9]*' 389 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 390 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' 391 | VariableMaxLength: 392 | active: false 393 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 394 | maximumVariableNameLength: 64 395 | VariableMinLength: 396 | active: false 397 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 398 | minimumVariableNameLength: 1 399 | VariableNaming: 400 | active: true 401 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 402 | variablePattern: '[a-z][A-Za-z0-9]*' 403 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' 404 | excludeClassPattern: '$^' 405 | ignoreOverridden: true 406 | 407 | performance: 408 | active: true 409 | ArrayPrimitive: 410 | active: true 411 | ForEachOnRange: 412 | active: true 413 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 414 | SpreadOperator: 415 | active: true 416 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 417 | UnnecessaryTemporaryInstantiation: 418 | active: true 419 | 420 | potential-bugs: 421 | active: true 422 | Deprecation: 423 | active: true 424 | DuplicateCaseInWhenExpression: 425 | active: true 426 | EqualsAlwaysReturnsTrueOrFalse: 427 | active: true 428 | EqualsWithHashCodeExist: 429 | active: true 430 | ExplicitGarbageCollectionCall: 431 | active: true 432 | HasPlatformType: 433 | active: true 434 | ImplicitDefaultLocale: 435 | active: false 436 | InvalidRange: 437 | active: true 438 | IteratorHasNextCallsNextMethod: 439 | active: true 440 | IteratorNotThrowingNoSuchElementException: 441 | active: true 442 | LateinitUsage: 443 | active: false 444 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 445 | excludeAnnotatedProperties: [] 446 | ignoreOnClassesPattern: '' 447 | MapGetWithNotNullAssertionOperator: 448 | active: true 449 | MissingWhenCase: 450 | active: true 451 | RedundantElseInWhen: 452 | active: true 453 | UnconditionalJumpStatementInLoop: 454 | active: true 455 | UnnecessaryNotNullOperator: 456 | active: true 457 | UnnecessarySafeCall: 458 | active: true 459 | UnreachableCode: 460 | active: true 461 | UnsafeCallOnNullableType: 462 | active: true 463 | UnsafeCast: 464 | active: false 465 | UselessPostfixExpression: 466 | active: true 467 | WrongEqualsTypeParameter: 468 | active: true 469 | 470 | style: 471 | active: true 472 | CollapsibleIfStatements: 473 | active: true 474 | DataClassContainsFunctions: 475 | active: false 476 | conversionFunctionPrefix: 'to' 477 | DataClassShouldBeImmutable: 478 | active: true 479 | EqualsNullCall: 480 | active: true 481 | EqualsOnSignatureLine: 482 | active: true 483 | ExplicitCollectionElementAccessMethod: 484 | active: true 485 | ExplicitItLambdaParameter: 486 | active: true 487 | # TODO: https://github.com/detekt/detekt/issues/950#issuecomment-401575701 488 | ExpressionBodySyntax: 489 | active: false 490 | includeLineWrapping: false 491 | ForbiddenComment: 492 | active: true 493 | values: ['FIXME' , 'STOPSHIP'] 494 | allowedPatterns: '' 495 | ForbiddenImport: 496 | active: false 497 | imports: [] 498 | forbiddenPatterns: '' 499 | ForbiddenMethodCall: 500 | active: false 501 | methods: [] 502 | ForbiddenPublicDataClass: 503 | active: false 504 | ignorePackages: ['*.internal', '*.internal.*'] 505 | ForbiddenVoid: 506 | active: true 507 | ignoreOverridden: false 508 | ignoreUsageInGenerics: false 509 | FunctionOnlyReturningConstant: 510 | active: true 511 | ignoreOverridableFunction: true 512 | excludedFunctions: 'describeContents' 513 | excludeAnnotatedFunction: ['dagger.Provides'] 514 | LibraryCodeMustSpecifyReturnType: 515 | active: true 516 | LoopWithTooManyJumpStatements: 517 | active: true 518 | maxJumpCount: 1 519 | MagicNumber: 520 | active: true 521 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 522 | ignoreNumbers: ['-1', '0', '0.5', '1', '2'] 523 | ignoreHashCodeFunction: true 524 | ignorePropertyDeclaration: false 525 | ignoreLocalVariableDeclaration: false 526 | ignoreConstantDeclaration: true 527 | ignoreCompanionObjectPropertyDeclaration: true 528 | ignoreAnnotation: false 529 | ignoreNamedArgument: true 530 | ignoreEnums: false 531 | ignoreRanges: false 532 | MandatoryBracesIfStatements: 533 | active: false # See formatting.MultiLineIfElse 534 | MandatoryBracesLoops: 535 | active: true 536 | MaxLineLength: 537 | active: true 538 | maxLineLength: 120 539 | excludePackageStatements: true 540 | excludeImportStatements: true 541 | excludeCommentStatements: false 542 | MayBeConst: 543 | active: true 544 | ModifierOrder: 545 | active: true 546 | NestedClassesVisibility: 547 | active: true 548 | NewLineAtEndOfFile: 549 | active: true 550 | NoTabs: 551 | active: true 552 | OptionalAbstractKeyword: 553 | active: true 554 | OptionalUnit: 555 | active: true 556 | OptionalWhenBraces: 557 | active: false 558 | PreferToOverPairSyntax: 559 | active: true 560 | ProtectedMemberInFinalClass: 561 | active: true 562 | RedundantExplicitType: 563 | active: true 564 | RedundantVisibilityModifierRule: 565 | active: true 566 | ReturnCount: 567 | active: true 568 | max: 2 569 | excludedFunctions: 'equals' 570 | excludeLabeled: false 571 | excludeReturnFromLambda: true 572 | excludeGuardClauses: false 573 | SafeCast: 574 | active: true 575 | SerialVersionUIDInSerializableClass: 576 | active: false 577 | SpacingBetweenPackageAndImports: 578 | active: false # See formatting.NoConsecutiveBlankLines 579 | ThrowsCount: 580 | active: true 581 | max: 2 582 | TrailingWhitespace: 583 | active: false # See formatting.NoTrailingWhitespace 584 | UnderscoresInNumericLiterals: 585 | active: true 586 | acceptableDecimalLength: 5 587 | UnnecessaryAbstractClass: 588 | active: true 589 | excludeAnnotatedClasses: ['dagger.Module'] 590 | UnnecessaryAnnotationUseSiteTarget: 591 | active: true 592 | UnnecessaryApply: 593 | active: true 594 | UnnecessaryInheritance: 595 | active: true 596 | UnnecessaryLet: 597 | active: true 598 | UnnecessaryParentheses: 599 | active: true 600 | UntilInsteadOfRangeTo: 601 | active: true 602 | UnusedImports: 603 | active: false # See formatting.NoUnusedImports 604 | UnusedPrivateClass: 605 | active: true 606 | UnusedPrivateMember: 607 | active: true 608 | allowedNames: '(_|ignored|expected|serialVersionUID)' 609 | UseArrayLiteralsInAnnotations: 610 | active: true 611 | UseCheckOrError: 612 | active: true 613 | UseDataClass: 614 | active: false 615 | excludeAnnotatedClasses: [] 616 | allowVars: false 617 | UseIfInsteadOfWhen: 618 | active: true 619 | UseRequire: 620 | active: true 621 | UselessCallOnNotNull: 622 | active: true 623 | UtilityClassWithPublicConstructor: 624 | active: true 625 | VarCouldBeVal: 626 | active: true 627 | WildcardImport: 628 | active: false 629 | excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt'] 630 | excludeImports: ['java.util.*', 'kotlinx.android.synthetic.*'] 631 | --------------------------------------------------------------------------------