├── sectionsDecorator
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── values
│ │ │ └── dimens.xml
│ │ └── layout
│ │ │ └── section_header.xml
│ │ └── java
│ │ └── co
│ │ └── netguru
│ │ └── sectionsDecorator
│ │ ├── SectionAdapterInterface.kt
│ │ ├── Extentions.kt
│ │ ├── VerticalPainter.kt
│ │ ├── HorizontalPainter.kt
│ │ ├── Painter.kt
│ │ └── SectionDecorator.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── app
├── src
│ ├── test
│ │ └── resources
│ │ │ └── mockito-extensions
│ │ │ └── org.mockito.plugins.MockMaker
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── drawable
│ │ │ │ ├── splash_background.xml
│ │ │ │ ├── ic_panorama_horizontal_black_24dp.xml
│ │ │ │ └── ic_panorama_vertical_black_24dp.xml
│ │ │ ├── layout
│ │ │ │ ├── list_item_vertical.xml
│ │ │ │ ├── list_item_horizontal.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── fragment_vertical.xml
│ │ │ │ └── fragment_horizontal.xml
│ │ │ └── menu
│ │ │ │ └── bottom_navigation_main.xml
│ │ ├── ic_launcher-web.png
│ │ ├── kotlin
│ │ │ └── co
│ │ │ │ └── netguru
│ │ │ │ └── android
│ │ │ │ └── sectionsDecoratorDemo
│ │ │ │ ├── application
│ │ │ │ ├── scope
│ │ │ │ │ ├── AppScope.kt
│ │ │ │ │ ├── ActivityScope.kt
│ │ │ │ │ └── FragmentScope.kt
│ │ │ │ ├── ApplicationModule.kt
│ │ │ │ ├── ApplicationComponent.kt
│ │ │ │ ├── App.kt
│ │ │ │ └── RxJavaErrorHandler.kt
│ │ │ │ ├── common
│ │ │ │ ├── extensions
│ │ │ │ │ ├── SharedPreferencesExtensions.kt
│ │ │ │ │ ├── ActivityExtentions.kt
│ │ │ │ │ ├── ContextExtensions.kt
│ │ │ │ │ └── RxExtensions.kt
│ │ │ │ └── Optional.kt
│ │ │ │ └── feature
│ │ │ │ ├── splash
│ │ │ │ └── SplashActivity.kt
│ │ │ │ └── demo
│ │ │ │ ├── HorizontalFragment.kt
│ │ │ │ ├── VerticalFragment.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── Adapter.kt
│ │ └── AndroidManifest.xml
│ ├── release
│ │ └── kotlin
│ │ │ └── co
│ │ │ └── netguru
│ │ │ └── android
│ │ │ └── sectionsDecoratorDemo
│ │ │ └── application
│ │ │ ├── RxJavaErrorHandlerImpl.kt
│ │ │ └── DebugMetricsHelper.kt
│ └── debug
│ │ └── kotlin
│ │ └── co
│ │ └── netguru
│ │ └── android
│ │ └── sectionsDecoratorDemo
│ │ └── application
│ │ ├── RxJavaErrorHandlerImpl.kt
│ │ └── DebugMetricsHelper.kt
├── proguard-rules-test.pro
├── proguard-rules.pro
└── build.gradle
├── images
├── example1.gif
└── example2.gif
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── vcs.xml
├── codeStyles
│ └── Project.xml
└── misc.xml
├── LICENSE
├── codecov.yml
├── README.md
├── gradlew.bat
├── .gitignore
├── gradlew
└── default-detekt-config.yml
/sectionsDecorator/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':sectionsDecorator'
2 |
--------------------------------------------------------------------------------
/app/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker:
--------------------------------------------------------------------------------
1 | mock-maker-inline
--------------------------------------------------------------------------------
/images/example1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/images/example1.gif
--------------------------------------------------------------------------------
/images/example2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/images/example2.gif
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/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/netguru/sections-decorator-android/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/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/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/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/sections-decorator-android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/scope/AppScope.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application.scope
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | annotation class AppScope
7 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/scope/ActivityScope.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application.scope
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | annotation class ActivityScope
7 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/scope/FragmentScope.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application.scope
2 |
3 | import javax.inject.Scope
4 |
5 | @Scope
6 | annotation class FragmentScope
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sections decorator
4 | Vertical
5 | Horizontal
6 |
7 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 24dp
4 | 24dp
5 | 1dp
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 11 10:02:25 CEST 2018
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-4.10.2-all.zip
7 |
--------------------------------------------------------------------------------
/app/proguard-rules-test.pro:
--------------------------------------------------------------------------------
1 | # Additional proguard rules for instrumentation testing
2 |
3 | -keep class rx.plugins.** { *; }
4 | -keep class org.junit.** { *; }
5 | -keep class co.netguru.android.testcommons.** { *; }
6 | -keep class android.support.test.espresso.** { *; }
7 | -dontwarn org.hamcrest.**
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/SectionAdapterInterface.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | interface SectionsAdapterInterface {
4 | fun getSectionsCount() : Int
5 | fun getSectionTitleAt(sectionIndex: Int): String
6 | fun getItemCountForSection(sectionIndex: Int): Int
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #d81b60
6 | #FFFFFF
7 | #5FCF6F
8 |
9 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/res/layout/section_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/common/extensions/SharedPreferencesExtensions.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.common.extensions
2 |
3 | import android.content.SharedPreferences
4 |
5 | inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {
6 | val editor = edit()
7 | editor.action()
8 | editor.apply()
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/splash_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/ApplicationModule.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import co.netguru.android.sectionsDecoratorDemo.application.scope.AppScope
4 | import dagger.Module
5 | import dagger.Provides
6 |
7 | @Module
8 | class ApplicationModule {
9 |
10 | @AppScope
11 | @Provides
12 | fun rxJavaErrorHandler(): RxJavaErrorHandler = RxJavaErrorHandlerImpl()
13 | }
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2018 Netguru
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 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/splash/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.feature.splash
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import co.netguru.android.sectionsDecoratorDemo.common.extensions.startActivity
6 | import co.netguru.android.sectionsDecoratorDemo.feature.demo.DemoActivity
7 |
8 | class SplashActivity : AppCompatActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | startActivity()
12 | finish()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/common/extensions/ActivityExtentions.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.common.extensions
2 |
3 | import android.support.annotation.IdRes
4 | import android.support.v4.app.Fragment
5 | import android.support.v4.app.FragmentManager
6 |
7 | fun FragmentManager.replaceFragment(
8 | @IdRes container: Int,
9 | tag: String,
10 | createFragment: () -> Fragment
11 | ) {
12 | val foundFragment = findFragmentByTag(tag) ?: createFragment()
13 | val transaction = beginTransaction()
14 | transaction.replace(container, foundFragment)
15 | transaction.commit()
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/ApplicationComponent.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import co.netguru.android.sectionsDecoratorDemo.application.scope.AppScope
4 | import dagger.Component
5 | import dagger.android.AndroidInjector
6 | import dagger.android.support.AndroidSupportInjectionModule
7 |
8 | @AppScope
9 | @Component(
10 | modules = [
11 | AndroidSupportInjectionModule::class,
12 | ApplicationModule::class
13 | ]
14 | )
15 | internal interface ApplicationComponent : AndroidInjector {
16 | @Component.Builder
17 | abstract class Builder : AndroidInjector.Builder()
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/bottom_navigation_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
--------------------------------------------------------------------------------
/app/src/release/kotlin/co/netguru/android/sectionsDecoratorDemo/application/RxJavaErrorHandlerImpl.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import io.reactivex.exceptions.UndeliverableException
4 | import timber.log.Timber
5 |
6 | class RxJavaErrorHandlerImpl : RxJavaErrorHandler() {
7 |
8 | override fun handleUndeliverableException(undeliverableException: UndeliverableException) {
9 | //TODO - decide whether this should be logged and passed or not to used crash reporter
10 | //often occurring might be indication of some problem in library or our codebase but definitely shouldn't crash the app
11 | //Crashlytics.logException(undeliverableException)
12 | Timber.e(undeliverableException)
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/release/kotlin/co/netguru/android/sectionsDecoratorDemo/application/DebugMetricsHelper.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import android.content.Context
4 | import co.netguru.android.sectionsDecoratorDemo.application.scope.AppScope
5 | import javax.inject.Inject
6 |
7 | /**
8 | * Helper class that initializes a set of debugging tools
9 | * for the debug build type and register crash manager for release type.
10 | * ## Debug type tools:
11 | * - AndroidDevMetrics
12 | * - Stetho
13 | * - StrictMode
14 | * - LeakCanary
15 | * - Timber
16 | *
17 | * ## Release type tools:
18 | * - CrashManager
19 | */
20 | @AppScope
21 | class DebugMetricsHelper @Inject constructor() {
22 |
23 | internal fun init(context: Context) = Unit
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/debug/kotlin/co/netguru/android/sectionsDecoratorDemo/application/RxJavaErrorHandlerImpl.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import io.reactivex.exceptions.UndeliverableException
4 |
5 | class RxJavaErrorHandlerImpl : RxJavaErrorHandler() {
6 |
7 | override fun handleUndeliverableException(undeliverableException: UndeliverableException) {
8 | /**
9 | * Crash the app while in debug as undeliverable exception can sometimes be indication of
10 | * bug's that could have been prevented. Check if disposables/cancelables are set properly
11 | * on emitter or backup with tryOnError from emitter if that's not possible.
12 | */
13 | undeliverableException.printStackTrace()
14 | uncaught(undeliverableException)
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/App.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import dagger.android.AndroidInjector
4 | import dagger.android.support.DaggerApplication
5 | import io.reactivex.plugins.RxJavaPlugins
6 | import javax.inject.Inject
7 |
8 | class App : DaggerApplication() {
9 |
10 | @Inject
11 | lateinit var debugMetricsHelper: DebugMetricsHelper
12 |
13 | @Inject
14 | lateinit var rxJavaErrorHandler: RxJavaErrorHandler
15 |
16 | override fun onCreate() {
17 | super.onCreate()
18 | debugMetricsHelper.init(this)
19 | RxJavaPlugins.setErrorHandler(rxJavaErrorHandler)
20 | }
21 |
22 | override fun applicationInjector(): AndroidInjector =
23 | DaggerApplicationComponent.builder().create(this)
24 | }
25 |
--------------------------------------------------------------------------------
/sectionsDecorator/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_panorama_horizontal_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_panorama_vertical_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_vertical.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/sectionsDecorator/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'com.github.dcendents.android-maven'
5 |
6 | group = 'com.github.netguru'
7 |
8 | android {
9 | compileSdkVersion 27
10 |
11 | defaultConfig {
12 | minSdkVersion 17
13 | targetSdkVersion 27
14 | versionCode 1
15 | versionName "0.1.1"
16 | consumerProguardFiles 'proguard-rules.pro'
17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | // TODO replace with https://issuetracker.google.com/issues/72050365 once released.
21 | libraryVariants.all {
22 | it.generateBuildConfig.enabled = false
23 | }
24 | }
25 |
26 | androidExtensions {
27 | experimental = true
28 | }
29 |
30 | dependencies {
31 | implementation libs.recyclerView
32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
33 | }
34 | repositories {
35 | mavenCentral()
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_horizontal.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | ci:
3 | - bitrise
4 |
5 | coverage:
6 | precision: 2
7 | round: down
8 | range: "0...100"
9 |
10 | status:
11 | project:
12 | unit:
13 | target: auto
14 | threshold: 1%
15 | flag: unit
16 | flags:
17 | - unit
18 |
19 | instrumentation:
20 | target: auto
21 | threshold: 1%
22 | flag: instrumentation
23 | flags:
24 | - instrumentation
25 | patch:
26 | unit:
27 | flag: unit
28 | flags:
29 | - unit
30 |
31 | instrumentation:
32 | flag: instrumentation
33 | flags:
34 | - instrumentation
35 |
36 | changes:
37 | unit:
38 | flag: unit
39 | flags:
40 | - unit
41 |
42 | instrumentation:
43 | flag: instrumentation
44 | flags:
45 | - instrumentation
46 |
47 | ignore:
48 | - mock/*
49 | - production/*
50 | - androidTest/*
51 | - androidTestMock/*
52 | - androidTestProduction/*
53 |
54 | comment:
55 | layout: "header, diff, changes, sunburst, uncovered"
56 | behavior: default
57 | flags:
58 | - unit
59 | - instrumentation
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/common/extensions/ContextExtensions.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.common.extensions
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.support.annotation.AttrRes
7 | import android.support.annotation.ColorRes
8 | import android.support.annotation.DrawableRes
9 | import android.support.v4.content.ContextCompat
10 | import android.util.TypedValue
11 |
12 | inline fun Context.startActivity() {
13 | val intent = Intent(this, T::class.java)
14 | startActivity(intent)
15 | }
16 |
17 | fun Context.getColorCompat(@ColorRes color: Int) = ContextCompat.getColor(this, color)
18 |
19 | fun Context.getDrawableCompat(@DrawableRes drawable: Int) =
20 | ContextCompat.getDrawable(this, drawable)
21 |
22 | fun Context.getAttributeColor(@AttrRes attrColor: Int): Int {
23 | val typedValue = TypedValue()
24 | theme.resolveAttribute(attrColor, typedValue, true)
25 | return typedValue.data
26 | }
27 |
28 | fun Context.getAttributeDrawable(@AttrRes attrDrawableRes: Int): Int {
29 | val typedValue = TypedValue()
30 | theme.resolveAttribute(attrDrawableRes, typedValue, true)
31 | return typedValue.resourceId
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/demo/HorizontalFragment.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.feature.demo
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.LinearLayout
9 | import co.netguru.android.sectionsDecoratorDemo.R
10 | import co.netguru.sectionsDecorator.SectionDecorator
11 | import kotlinx.android.synthetic.main.fragment_horizontal.*
12 |
13 | class HorizontalFragment : Fragment(){
14 | companion object {
15 | val TAG = HorizontalFragment::class.java.simpleName!!
16 | fun createFragment() = HorizontalFragment()
17 | }
18 |
19 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
20 | return inflater.inflate(R.layout.fragment_horizontal, container, false)
21 | }
22 |
23 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
24 | super.onViewCreated(view, savedInstanceState)
25 | recyclerView.adapter = MyAdapter(LinearLayout.HORIZONTAL)
26 | recyclerView.addItemDecoration(SectionDecorator(context!!).apply {
27 | setLineColor(R.color.green)
28 | setLineWidth(15f)
29 | })
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/demo/VerticalFragment.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.feature.demo
2 |
3 | import android.os.Bundle
4 | import android.support.v4.app.Fragment
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.LinearLayout
9 | import co.netguru.android.sectionsDecoratorDemo.R
10 | import co.netguru.sectionsDecorator.SectionDecorator
11 | import kotlinx.android.synthetic.main.fragment_horizontal.*
12 |
13 | class VerticalFragment : Fragment() {
14 |
15 | companion object {
16 | val TAG = VerticalFragment::class.java.simpleName!!
17 | fun createFragment() = VerticalFragment()
18 | }
19 |
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View? {
25 | return inflater.inflate(R.layout.fragment_vertical, container, false)
26 | }
27 |
28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
29 | super.onViewCreated(view, savedInstanceState)
30 | recyclerView.adapter = MyAdapter(LinearLayout.VERTICAL)
31 | recyclerView.addItemDecoration(SectionDecorator(context!!).apply {
32 | setLineColor(R.color.green)
33 | setLineWidth(15f)
34 | })
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/application/RxJavaErrorHandler.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import io.reactivex.exceptions.UndeliverableException
4 | import io.reactivex.functions.Consumer
5 |
6 | /**
7 | * [RxJava2 error handling](https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling)
8 | */
9 | abstract class RxJavaErrorHandler : Consumer {
10 |
11 | override fun accept(throwable: Throwable) = when (throwable) {
12 | is UndeliverableException -> {
13 | //we log such exceptions but avoid app crash for release as we can't do much in such case.
14 | handleUndeliverableException(throwable)
15 | }
16 | else -> {
17 | //we crash the app else - this is a bug
18 | throwable.printStackTrace()
19 | uncaught(throwable)
20 | }
21 | }
22 |
23 | /**
24 | * Something thrown error after stream finished.
25 | * If this happens often it can be indication of some problem in library or our codebase.
26 | * Make sure that source sets disposable/cancellable while creating stream.
27 | * You can also use tryOnError if the wrapped data source doesn't provide good way to cancel emissions.
28 | */
29 | abstract fun handleUndeliverableException(undeliverableException: UndeliverableException)
30 |
31 | protected fun uncaught(throwable: Throwable) {
32 | val currentThread = Thread.currentThread()
33 | val handler = currentThread.uncaughtExceptionHandler
34 | handler.uncaughtException(currentThread, throwable)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/Extentions.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | import android.content.Context
4 | import android.support.annotation.ColorRes
5 | import android.support.v4.content.ContextCompat
6 | import android.view.View
7 | import android.view.ViewGroup
8 |
9 | fun ViewGroup.asSequence(): Sequence = object : Sequence {
10 |
11 | override fun iterator(): Iterator = object : Iterator {
12 | private var nextValue: View? = null
13 | private var done = false
14 | private var position: Int = 0
15 |
16 | override fun hasNext(): Boolean {
17 | if (nextValue == null && !done) {
18 | nextValue = getChildAt(position)
19 | position++
20 | if (nextValue == null) done = true
21 | }
22 | return nextValue != null
23 | }
24 |
25 | override fun next(): View {
26 | if (!hasNext()) {
27 | throw NoSuchElementException()
28 | }
29 | val answer = nextValue
30 | nextValue = null
31 | return answer!!
32 | }
33 | }
34 | }
35 |
36 | fun Context.getColorCompat(@ColorRes color: Int) = ContextCompat.getColor(this, color)
37 |
38 | fun Map>.addToValueList(key: R, element: T): Map> {
39 | val mutable = this.toMutableMap()
40 | mutable[key] = (this[key] ?: emptyList()) + element
41 | return mutable
42 | }
43 |
44 | inline fun nullCheck2(item1: A?, item2: B?, f: (A, B) -> Unit) {
45 | if (item1 != null && item2 != null) {
46 | f(item1, item2)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/common/extensions/RxExtensions.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.common.extensions
2 |
3 | import io.reactivex.*
4 |
5 | import io.reactivex.android.schedulers.AndroidSchedulers
6 | import io.reactivex.schedulers.Schedulers
7 |
8 | fun Completable.applyIoSchedulers() = this.subscribeOn(Schedulers.io())
9 | .observeOn(AndroidSchedulers.mainThread())
10 |
11 | fun Completable.applyComputationSchedulers() = this.subscribeOn(Schedulers.computation())
12 | .observeOn(AndroidSchedulers.mainThread())
13 |
14 | fun Maybe.applyIoSchedulers() = this.subscribeOn(Schedulers.io())
15 | .observeOn(AndroidSchedulers.mainThread())
16 |
17 | fun Maybe.applyComputationSchedulers() = this.subscribeOn(Schedulers.computation())
18 | .observeOn(AndroidSchedulers.mainThread())
19 |
20 | fun Single.applyIoSchedulers() = this.subscribeOn(Schedulers.io())
21 | .observeOn(AndroidSchedulers.mainThread())
22 |
23 | fun Single.applyComputationSchedulers() = this.subscribeOn(Schedulers.computation())
24 | .observeOn(AndroidSchedulers.mainThread())
25 |
26 | fun Observable.applyIoSchedulers() = this.subscribeOn(Schedulers.io())
27 | .observeOn(AndroidSchedulers.mainThread())
28 |
29 | fun Observable.applyComputationSchedulers() = this.subscribeOn(Schedulers.computation())
30 | .observeOn(AndroidSchedulers.mainThread())
31 |
32 | fun Flowable.applyIoSchedulers(): Flowable = this.subscribeOn(Schedulers.io())
33 | .observeOn(AndroidSchedulers.mainThread())
34 |
35 | fun Flowable.applyComputationSchedulers(): Flowable =
36 | this.subscribeOn(Schedulers.computation())
37 | .observeOn(AndroidSchedulers.mainThread())
38 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/demo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.feature.demo
2 |
3 |
4 | import android.os.Bundle
5 | import android.support.v7.app.AppCompatActivity
6 | import co.netguru.android.sectionsDecoratorDemo.R
7 | import co.netguru.android.sectionsDecoratorDemo.common.extensions.replaceFragment
8 | import co.netguru.android.sectionsDecoratorDemo.feature.demo.HorizontalFragment.Companion.createFragment
9 | import kotlinx.android.synthetic.main.activity_main.*
10 |
11 | class DemoActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setContentView(R.layout.activity_main)
16 |
17 | supportFragmentManager.replaceFragment(
18 | R.id.content,
19 | HorizontalFragment.TAG,
20 | HorizontalFragment.Companion::createFragment
21 | )
22 |
23 | bottomNavigation.setOnNavigationItemSelectedListener {
24 | when (it.itemId) {
25 | R.id.vertical -> {
26 | supportFragmentManager.replaceFragment(
27 | R.id.content,
28 | VerticalFragment.TAG,
29 | VerticalFragment.Companion::createFragment
30 | )
31 | }
32 | R.id.horizontal -> {
33 | supportFragmentManager.replaceFragment(
34 | R.id.content,
35 | HorizontalFragment.TAG,
36 | HorizontalFragment.Companion::createFragment
37 | )
38 | }
39 | }
40 | return@setOnNavigationItemSelectedListener true
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/debug/kotlin/co/netguru/android/sectionsDecoratorDemo/application/DebugMetricsHelper.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.application
2 |
3 | import android.content.Context
4 | import co.netguru.android.sectionsDecoratorDemo.application.scope.AppScope
5 | import com.facebook.stetho.Stetho
6 | import com.github.moduth.blockcanary.BlockCanary
7 | import com.github.moduth.blockcanary.BlockCanaryContext
8 | import com.squareup.leakcanary.LeakCanary
9 | import timber.log.Timber
10 | import javax.inject.Inject
11 |
12 | /**
13 | * Helper class that initializes a set of debugging tools
14 | * for the debug build type and register crash manager for release type.
15 | * ## Debug type tools:
16 | * - AndroidDevMetrics
17 | * - Stetho
18 | * - StrictMode
19 | * - LeakCanary
20 | * - Timber
21 | *
22 | * ## Release type tools:
23 | * - CrashManager
24 | */
25 | @AppScope
26 | class DebugMetricsHelper @Inject constructor() {
27 |
28 | internal fun init(context: Context) {
29 | // LeakCanary
30 | if (LeakCanary.isInAnalyzerProcess(context.applicationContext as App)) {
31 | // This process is dedicated to LeakCanary for heap analysis.
32 | // You should not init your app in this process.
33 | return
34 | }
35 | LeakCanary.install(context.applicationContext as App)
36 |
37 | // Stetho
38 | Stetho.initialize(
39 | Stetho.newInitializerBuilder(context)
40 | .enableDumpapp(Stetho.defaultDumperPluginsProvider(context))
41 | .enableWebKitInspector(Stetho.defaultInspectorModulesProvider(context))
42 | .build()
43 | )
44 |
45 | //Timber
46 | Timber.plant(Timber.DebugTree())
47 |
48 | //BlockCanary
49 | BlockCanary.install(context, BlockCanaryContext()).start()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
18 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/common/Optional.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.common
2 |
3 | import io.reactivex.Maybe
4 | import io.reactivex.Observable
5 | import io.reactivex.Single
6 | import io.reactivex.rxkotlin.ofType
7 |
8 | /**
9 | * Optional implementation intended to be used together with Rx2 which doesn't accept nulls.
10 | */
11 | sealed class Optional {
12 |
13 | fun toNullable(): T? = when (this) {
14 | is Some -> value
15 | is None -> null
16 | }
17 |
18 | data class Some(val value: T) : Optional()
19 | object None : Optional()
20 |
21 | /**
22 | * If a value is present, apply the provided mapping function to it,
23 | * and if the result is non-null, return an [Optional.Some] describing the
24 | * result. Otherwise return an empty [Optional.None].
25 | */
26 | inline fun map(f: (T) -> U?): Optional = when (this) {
27 | is Optional.Some -> f(value).toOptional()
28 | Optional.None -> None
29 | }
30 |
31 | /**
32 | * If a value is present, apply the provided [Optional]-bearing
33 | * mapping function to it, return that result, otherwise return an empty
34 | * [Optional.None]. This method is similar to [Optional.map],
35 | * but the provided mapper is one whose result is already an [Optional].
36 | */
37 | inline fun flatMap(f: (T) -> Optional): Optional = when (this) {
38 | is Optional.Some -> f(value)
39 | Optional.None -> None
40 | }
41 | }
42 |
43 | fun T?.toOptional(): Optional = if (this == null) Optional.None else Optional.Some(
44 | this
45 | )
46 |
47 | fun Observable>.filterOptionalNone(): Observable =
48 | this.ofType>()
49 | .map { it.toNullable() }
50 |
51 | fun Single>.filterOptionalNone(): Maybe =
52 | this.filter { it is Optional.Some }
53 | .map { it.toNullable() }
54 |
55 | fun Maybe>.filterOptionalNone(): Maybe =
56 | this.filter { it is Optional.Some }
57 | .map { it.toNullable() }
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sections decorator
2 |
3 | ## About
4 | Sections decorator is RecyclerView decorator that decorates multi section recycler with vertical / horizontal line and section title.
5 | Current section title is always visible. It might be useful in todo list or calendar like applications.
6 |  
7 |
8 | ## Usage
9 |
10 | 1. Add jitpack.io to your build.gradle
11 | ```groovy
12 | repositories {
13 | mavenCentral()
14 | maven { url 'https://jitpack.io' }
15 | }
16 | ```
17 | 2. Add library dependency
18 | ```groovy
19 | implementation 'com.github.netguru:sections-decorator-android:0.1.1'
20 | ```
21 |
22 | 3. implement SectionsAdapterInterface in your RecyclerView adapter
23 | - see example in [Sample app](app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/demo/Adapter.kt)
24 |
25 | 4. add decorator to your RecyclerView
26 |
27 | kotlin:
28 | ```kotlin
29 | recyclerView.addItemDecoration(SectionDecorator(context).apply {
30 | setLineColor(R.color.green)
31 | setLineWidth(15f)
32 | })
33 | ```
34 |
35 | java:
36 | ```java
37 | SectionDecorator decorator = new SectionDecorator(getContext());
38 | decorator.setLineColor(R.color.green)
39 | decorator.setLineWidth(15f)
40 | recyclerView.addItemDecoration(decorator);
41 | ```
42 | 5. Customize
43 |
44 | ## Customization
45 | you can customize line color and width through `setLineColor(color: Int)` and `setLineWidth(width: Float)`.
46 | To customize text appearience you can create layout with only TextView in it and pass it to decorator using
47 | `setHeaderView(layoutRes: Int)`
48 |
49 | ## License
50 | ```
51 | Copyright 2018 Netguru
52 |
53 | Licensed under the Apache License, Version 2.0 (the "License");
54 | you may not use this file except in compliance with the License.
55 | You may obtain a copy of the License at
56 |
57 | http://www.apache.org/licenses/LICENSE-2.0
58 |
59 | Unless required by applicable law or agreed to in writing, software
60 | distributed under the License is distributed on an "AS IS" BASIS,
61 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
62 | See the License for the specific language governing permissions and
63 | limitations under the License.
64 | ```
65 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/VerticalPainter.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import android.graphics.Rect
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 | import kotlin.math.max
10 | import kotlin.math.min
11 |
12 | class VerticalPainter(
13 | fixLayoutSize: (View, ViewGroup) -> Unit,
14 | headerToLineOffset: Float,
15 | linePaint: Paint
16 | ) : Painter(fixLayoutSize, headerToLineOffset, linePaint) {
17 |
18 |
19 | override fun getLineStart(sectionIndex: Int, first: View): Float {
20 | val topMargin =
21 | (first.layoutParams as ViewGroup.MarginLayoutParams).topMargin.toFloat()
22 | return if (sectionIndex == 0) {
23 | topMargin
24 | } else {
25 | max(first.top.toFloat(), topMargin)
26 | }
27 | }
28 |
29 | override fun getLineEnd(
30 | sectionIndex: Int,
31 | sectionSize: Int,
32 | canvas: Canvas,
33 | last: View
34 | ): Float {
35 | val bottomMargin =
36 | (last.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin.toFloat()
37 |
38 | return if (sectionIndex == sectionSize - 1) {
39 | canvas.height.toFloat() - bottomMargin
40 | } else {
41 | min(last.bottom.toFloat(), canvas.height.toFloat() - bottomMargin)
42 | }
43 | }
44 |
45 | override fun getXStart(sectionIndex: Int, first: View) = headerToLineOffset
46 | override fun getYStart(sectionIndex: Int, first: View) = getLineStart(sectionIndex, first)
47 |
48 | override fun getXEnd(sectionIndex: Int, sectionSize: Int, canvas: Canvas, last: View) =
49 | headerToLineOffset
50 |
51 | override fun getYEnd(sectionIndex: Int, sectionSize: Int, canvas: Canvas, last: View) =
52 | getLineEnd(sectionIndex, sectionSize, canvas, last)
53 |
54 | override fun drawHeader(
55 | canvas: Canvas,
56 | textView: TextView,
57 | startPosition: Float,
58 | headerWidth: Int
59 | ) {
60 | canvas.save()
61 | canvas.translate(0f, startPosition + headerWidth)
62 | canvas.rotate(-90f)
63 | textView.draw(canvas)
64 | canvas.restore()
65 | }
66 |
67 | override fun getOutRect(outRect: Rect) {
68 | outRect.left = headerToLineOffset.toInt()
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/HorizontalPainter.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import android.graphics.Rect
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 | import kotlin.math.max
10 | import kotlin.math.min
11 |
12 | class HorizontalPainter(
13 | fixLayoutSize: (View, ViewGroup) -> Unit,
14 | headerToLineOffset: Float,
15 | linePaint: Paint
16 | ) : Painter(fixLayoutSize, headerToLineOffset, linePaint) {
17 |
18 |
19 | override fun getLineStart(sectionIndex: Int, first: View): Float {
20 | val leftMargin =
21 | (first.layoutParams as ViewGroup.MarginLayoutParams).leftMargin.toFloat()
22 |
23 | return if (sectionIndex == 0) {
24 | leftMargin
25 | } else {
26 | max(first.left.toFloat(), leftMargin)
27 | }
28 | }
29 |
30 | override fun getLineEnd(
31 | sectionIndex: Int,
32 | sectionSize: Int,
33 | canvas: Canvas,
34 | last: View
35 | ): Float {
36 | val rightMargin =
37 | (last.layoutParams as ViewGroup.MarginLayoutParams).rightMargin.toFloat()
38 | return if (sectionIndex == sectionSize - 1) {
39 | canvas.width.toFloat() - rightMargin
40 | } else {
41 | min(last.right.toFloat(), canvas.width.toFloat() - rightMargin)
42 | }
43 |
44 | }
45 |
46 |
47 | override fun getXStart(sectionIndex: Int, first: View) = getLineStart(sectionIndex, first)
48 |
49 | override fun getXEnd(
50 | sectionIndex: Int,
51 | sectionSize: Int,
52 | canvas: Canvas,
53 | last: View
54 | ) = getLineEnd(sectionIndex, sectionSize, canvas, last)
55 |
56 | override fun getYStart(sectionIndex: Int, first: View) = headerToLineOffset
57 |
58 | override fun getYEnd(
59 | sectionIndex: Int,
60 | sectionSize: Int,
61 | canvas: Canvas,
62 | last: View
63 | ) = headerToLineOffset
64 |
65 | override fun getOutRect(outRect: Rect) {
66 | outRect.top = headerToLineOffset.toInt()
67 | }
68 |
69 | override fun drawHeader(
70 | canvas: Canvas,
71 | textView: TextView,
72 | startPosition: Float,
73 | headerWidth: Int
74 | ) {
75 | canvas.save()
76 | canvas.translate(startPosition, 0f)
77 | textView.draw(canvas)
78 | canvas.restore()
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/co/netguru/android/sectionsDecoratorDemo/feature/demo/Adapter.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.android.sectionsDecoratorDemo.feature.demo
2 |
3 | import android.graphics.Color
4 | import android.support.v7.widget.RecyclerView
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.LinearLayout
9 | import co.netguru.android.sectionsDecoratorDemo.R
10 | import co.netguru.sectionsDecorator.SectionsAdapterInterface
11 | import kotlinx.android.synthetic.main.list_item_horizontal.view.*
12 |
13 | class MyAdapter(val orientation: Int) : RecyclerView.Adapter(),
14 | SectionsAdapterInterface {
15 |
16 | private val items = linkedMapOf(
17 | Pair("Section 1", listOf("one 1", "two 1", "three 1", "four 1", "five 1", "six 1", "seven 1", "eight 1", "nine 1", "ten 1")),
18 | Pair("Middle", listOf("middle")),
19 | Pair("Section 2", listOf("one 2", "two 2", "three 2", "four 2", "five 2", "six 2", "seven 2", "eight 2", "nine 2", "ten 2"))
20 | )
21 |
22 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
23 | val layout = if (orientation == LinearLayout.HORIZONTAL) {
24 | R.layout.list_item_horizontal
25 | } else {
26 | R.layout.list_item_vertical
27 | }
28 | return MyViewHolder(LayoutInflater.from(parent.context).inflate(layout, parent, false))
29 | }
30 |
31 | override fun getItemCount(): Int {
32 | return items.values.flatten().size
33 | }
34 |
35 | override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
36 | val sectionNameOfItem = items.entries.flatMap { entry -> entry.value.map { Pair(entry.key, it) } }[position].first
37 | holder.bind(
38 | items.values.flatten()[position],
39 | items.keys.asSequence().toList().indexOf(sectionNameOfItem)
40 | )
41 | }
42 |
43 | override fun getSectionsCount(): Int {
44 | return items.keys.size
45 | }
46 |
47 | override fun getSectionTitleAt(sectionIndex: Int): String {
48 | return items.keys.toList()[sectionIndex]
49 | }
50 |
51 | override fun getItemCountForSection(sectionIndex: Int): Int {
52 | return (items[items.keys.toList()[sectionIndex]] ?: emptyList()).size
53 | }
54 | }
55 |
56 | class MyViewHolder(val view: View): RecyclerView.ViewHolder(view){
57 | private val textView = view.item_text!!
58 |
59 | fun bind(text: String, section: Int){
60 | if (section.rem(2) == 0) {
61 | view.setBackgroundColor(Color.CYAN)
62 | } else {
63 | view.setBackgroundColor(Color.LTGRAY)
64 | }
65 | textView.text = text
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Android
2 |
3 | # Built application files
4 | *.apk
5 | *.ap_
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Local configuration file (sdk path, etc)
23 | local.properties
24 |
25 | # Application secrets
26 | secret.properties
27 |
28 | Proguard folder generated by Eclipse
29 | #proguard/
30 |
31 | # Log Files
32 | *.log
33 |
34 | # Android Studio Navigation editor temp files
35 | .navigation/
36 |
37 | # Android Studio captures folder
38 | captures/
39 |
40 | # Keystore files
41 | *.jks
42 |
43 | ### JetBrains
44 |
45 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
46 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
47 |
48 | # IDEA/Android Studio ignores:
49 | *.iml
50 | *.ipr
51 | *.iws
52 | /.idea/*
53 | # IDEA/Android Studio Ignore exceptions
54 | !/.idea/vcs.xml
55 | !/.idea/fileTemplates/
56 | !/.idea/inspectionProfiles/
57 | !/.idea/scopes/
58 | !/.idea/codeStyleSettings.xml
59 | !/.idea/encodings.xml
60 | !/.idea/copyright/
61 | !/.idea/compiler.xml
62 | !/.idea/codeStyles
63 |
64 | # Project files backups generated on failures
65 | projectFilesBackup*/
66 |
67 | ## Plugin-specific files:
68 |
69 | # IntelliJ
70 | /out/
71 |
72 | # mpeltonen/sbt-idea plugin
73 | .idea_modules/
74 |
75 | # JIRA plugin
76 | atlassian-ide-plugin.xml
77 |
78 | # Crashlytics plugin (for Android Studio and IntelliJ)
79 | com_crashlytics_export_strings.xml
80 | crashlytics.properties
81 | crashlytics-build.properties
82 | fabric.properties
83 |
84 | # Firebase
85 | google-services.json
86 |
87 | ### Temporary files
88 |
89 | ## Vim
90 | [._]*.s[a-w][a-z]
91 | [._]s[a-w][a-z]
92 | Session.vim
93 | .netrwhist
94 | tags
95 |
96 | ## OS X
97 | *.DS_Store
98 | .AppleDouble
99 | .LSOverride
100 | # Icon must end with two \r
101 | Icon
102 | # Thumbnails
103 | ._*
104 | # Files that might appear in the root of a volume
105 | .DocumentRevisions-V100
106 | .fseventsd
107 | .Spotlight-V100
108 | .TemporaryItems
109 | .Trashes
110 | .VolumeIcon.icns
111 | .com.apple.timemachine.donotpresent
112 | # Directories potentially created on remote AFP share
113 | .AppleDB
114 | .AppleDesktop
115 | Network Trash Folder
116 | Temporary Items
117 | .apdisk
118 |
119 | ## Linux
120 | *~
121 |
122 | # temporary files which can be created if a process still has a handle open of a deleted file
123 | .fuse_hidden*
124 |
125 | # KDE directory preferences
126 | .directory
127 |
128 | # Linux trash folder which might appear on any partition or disk
129 | .Trash-*
130 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/Painter.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Paint
5 | import android.graphics.Rect
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 |
10 | abstract class Painter(
11 | internal val fixLayoutSize: (View, ViewGroup) -> Unit,
12 | internal val headerToLineOffset: Float,
13 | private val linePaint: Paint
14 | ) {
15 | abstract fun getOutRect(outRect: Rect)
16 |
17 | fun paint(
18 | canvas: Canvas,
19 | sectionIndex: Int,
20 | sectionTitle: String,
21 | sectionsVisibleElements: List,
22 | headerView: TextView,
23 | sectionSize: Int,
24 | parent: ViewGroup
25 | ) {
26 |
27 | val lineStart = getLineStart(sectionIndex, sectionsVisibleElements.first())
28 | val lineEnd = getLineEnd(sectionIndex, sectionSize, canvas, sectionsVisibleElements.last())
29 |
30 | if (lineEnd > lineStart) {
31 | canvas.drawLine(
32 | getXStart(sectionIndex, sectionsVisibleElements.first()),
33 | getYStart(sectionIndex, sectionsVisibleElements.first()),
34 | getXEnd(sectionIndex, sectionSize, canvas, sectionsVisibleElements.last()),
35 | getYEnd(sectionIndex, sectionSize, canvas, sectionsVisibleElements.last()),
36 | linePaint
37 | )
38 | }
39 |
40 | headerView.apply {
41 | text = sectionTitle
42 | fixLayoutSize(this, parent)
43 |
44 | val headerWidth = with(this) {
45 | width + paddingStart + paddingEnd +
46 | kotlin.with(layoutParams as ViewGroup.MarginLayoutParams) {
47 | marginStart + marginEnd
48 | }
49 | }
50 |
51 | val startPosition = if (lineEnd - lineStart < headerWidth && sectionIndex == 0) {
52 | lineEnd - headerWidth
53 | } else {
54 | lineStart
55 | }
56 |
57 | drawHeader(canvas, this, startPosition, headerWidth)
58 | }
59 | }
60 |
61 | internal abstract fun getLineStart(sectionIndex: Int, first: View): Float
62 | internal abstract fun getLineEnd(
63 | sectionIndex: Int,
64 | sectionSize: Int,
65 | canvas: Canvas,
66 | last: View
67 | ): Float
68 |
69 | internal abstract fun getXStart(sectionIndex: Int, first: View): Float
70 | internal abstract fun getXEnd(
71 | sectionIndex: Int,
72 | sectionSize: Int,
73 | canvas: Canvas,
74 | last: View
75 | ): Float
76 |
77 | internal abstract fun getYStart(sectionIndex: Int, first: View): Float
78 | internal abstract fun getYEnd(
79 | sectionIndex: Int,
80 | sectionSize: Int,
81 | canvas: Canvas,
82 | last: View
83 | ): Float
84 |
85 | internal abstract fun drawHeader(
86 | canvas: Canvas,
87 | textView: TextView,
88 | startPosition: Float,
89 | headerWidth: Int
90 | )
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/app/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/maciek/Library/Android/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 |
19 | # base option from *App Dev Note*
20 | -optimizationpasses 5
21 | -dontusemixedcaseclassnames
22 | -dontskipnonpubliclibraryclasses
23 | -dontskipnonpubliclibraryclassmembers
24 | -dontpreverify
25 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
26 | -keepattributes LineNumberTable,SourceFile,Signature,*Annotation*,Exceptions,InnerClasses
27 |
28 | # Keep native methods
29 | -keepclassmembers class * {
30 | native ;
31 | }
32 |
33 | # remove log call
34 | -assumenosideeffects class android.util.Log {
35 | public static *** d(...);
36 | }
37 | -assumenosideeffects class timber.log.Timber {
38 | public static *** d(...);
39 | }
40 |
41 | # Models!
42 | # TODO 07.09.2017 Rule should be adjusted to current project - all models used with GSON should keep their members name
43 | # TODO 07.09.2017 or all their members should be annotated with @SerializedName().
44 | -keepclassmembernames class co.netguru.android.template.data.**.model.** { *; }
45 |
46 | # app compat-v7
47 | -keep class android.support.v7.widget.SearchView { *; }
48 |
49 | # FragmentArgs
50 | -keep class com.hannesdorfmann.fragmentargs.** { *; }
51 |
52 | # Gson
53 | -keep class sun.misc.Unsafe { *; }
54 |
55 | # retrofit
56 | -keepclasseswithmembers class * {
57 | @retrofit2.http.* ;
58 | }
59 | -dontnote retrofit2.Platform
60 | -dontnote retrofit2.Platform$IOS$MainThreadExecutor
61 | -dontwarn retrofit2.Platform$Java8
62 | -keepattributes Signature
63 | -keepattributes Exceptions
64 |
65 | # dagger
66 | -keepclassmembers,allowobfuscation class * {
67 | @javax.inject.* *;
68 | @dagger.* *;
69 | ();
70 | }
71 | -keep class javax.inject.** { *; }
72 | -keep class **$$ModuleAdapter
73 | -keep class **$$InjectAdapter
74 | -keep class **$$StaticInjection
75 | -keep class dagger.** { *; }
76 | -dontwarn dagger.internal.codegen.**
77 |
78 | # stetho
79 | -dontwarn org.apache.http.**
80 | -keep class com.facebook.stetho.dumpapp.** { *; }
81 | -keep class com.facebook.stetho.server.** { *; }
82 | -dontwarn com.facebook.stetho.dumpapp.**
83 | -dontwarn com.facebook.stetho.server.**
84 |
85 | # leak canary
86 | -keep class org.eclipse.mat.** { *; }
87 | -keep class com.squareup.leakcanary.** { *; }
88 | -dontwarn android.app.Notification
89 |
90 | # fabric
91 | -dontwarn com.crashlytics.android.**
92 |
93 | # glide
94 | -keep public class * implements com.bumptech.glide.module.GlideModule
95 | -keep public class * extends com.bumptech.glide.AppGlideModule
96 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
97 | **[] $VALUES;
98 | public *;
99 | }
100 |
101 | -dontwarn okhttp3.**
102 | -dontwarn okio.**
103 | -dontwarn javax.annotation.**
104 |
105 | #dagger
106 | -dontwarn com.google.errorprone.annotations.*
--------------------------------------------------------------------------------
/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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 | apply plugin: 'kotlin-kapt'
5 | apply plugin: 'com.frogermcs.androiddevmetrics'
6 | apply plugin: 'com.getkeepsafe.dexcount'
7 | apply plugin: 'com.github.ben-manes.versions'
8 | apply plugin: 'org.sonarqube'
9 | apply plugin: 'com.vanniktech.android.junit.jacoco'
10 | apply from: '../buildsystem/sonarqube.gradle'
11 |
12 | android {
13 | compileSdkVersion 27
14 |
15 | defaultConfig {
16 | applicationId "co.netguru.android.sectionsDecorator"
17 | minSdkVersion 18
18 | targetSdkVersion 27
19 | versionCode isBitrise ? Integer.parseInt(bitrise.io.buildNumber) : 1
20 | versionName '0.1.1'
21 |
22 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
23 | }
24 |
25 | buildTypes {
26 | debug {
27 | versionNameSuffix "-DEBUG"
28 | applicationIdSuffix ".debug"
29 | testCoverageEnabled true
30 | debuggable true
31 | minifyEnabled true
32 | shrinkResources false
33 | useProguard false
34 | proguardFiles getDefaultProguardFile('proguard-android.txt'),
35 | 'proguard-rules.pro', 'proguard-rules-test.pro'
36 | }
37 | release {
38 | debuggable false
39 | minifyEnabled true
40 | shrinkResources true
41 | zipAlignEnabled true
42 | useProguard true
43 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
44 | 'proguard-rules.pro'
45 | }
46 | }
47 |
48 | // Always show the result of every unit test, even if it passes.
49 | testOptions.unitTests.all {
50 | testLogging {
51 | events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
52 | }
53 | }
54 |
55 | packagingOptions {
56 | exclude 'META-INF/services/javax.annotation.processing.Processor'
57 | exclude 'META-INF/LICENSE.txt'
58 | exclude 'META-INF/NOTICE.txt'
59 | }
60 |
61 | sourceSets.all {
62 | it.java.srcDir "src/$it.name/kotlin"
63 | }
64 |
65 | junitJacoco {
66 | jacocoVersion='0.7.9'
67 | excludes = ['android/databinding/**/*.class',
68 | '**/android/databinding/*Binding.class',
69 | '**/BR.*',
70 | '**/R.class',
71 | '**/R$*.class',
72 | '**/BuildConfig.*',
73 | '**/Manifest*.*',
74 | '**/*$ViewInjector*.*',
75 | '**/*$ViewBinder*.*',
76 | '**/*_MembersInjector.class',
77 | '**/Dagger*Component.class',
78 | '**/Dagger*Component$Builder.class',
79 | '**/*Module_*Factory.class',
80 | '**/AutoValue_*.*',
81 | '**/*JavascriptBridge.class',
82 | '**/Lambda$*.class',
83 | '**/Lambda.class',
84 | '**/*Lambda.class',
85 | '**/*Lambda*.class']
86 | }
87 |
88 | lintOptions {
89 | abortOnError false
90 | }
91 | }
92 |
93 | configurations {
94 | dependencyUpdates.resolutionStrategy = {
95 | componentSelection { rules ->
96 | rules.all { ComponentSelection selection ->
97 | boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier ->
98 | selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
99 | }
100 | if (rejected) {
101 | selection.reject('Release candidate')
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | dependencies {
109 |
110 | implementation project(":sectionsDecorator")
111 |
112 | //Kotlin
113 | implementation libs.kotlin
114 |
115 | // Anko Commons
116 | implementation libs.ankoCommons
117 | implementation libs.ankoCommonsSupportV7
118 | implementation libs.ankoCommonsSupportV4
119 |
120 | // Support
121 | implementation libs.appCompat
122 | implementation libs.recyclerView
123 | implementation libs.design
124 |
125 | // MVP
126 | implementation(libs.mosby) {
127 | exclude module: 'appcompat-v7'
128 | exclude module: 'support-annotations'
129 | }
130 |
131 | // Dagger
132 | implementation libs.dagger
133 | implementation libs.daggerAndroid
134 | implementation libs.daggerAndroidSupport
135 | kapt proc.dagger
136 | kapt proc.daggerAndroid
137 | compileOnly proc.javaxAnnotation
138 |
139 | //RxJava
140 | implementation libs.rxJava2
141 | implementation (libs.rxKotlin2) {
142 | exclude module: 'rxjava'
143 | exclude module: 'kotlin-stdlib'
144 | }
145 | implementation(libs.rxAndroid2) {
146 | exclude module: 'rxjava'
147 | }
148 |
149 | // OkHttp + Retrofit
150 | implementation libs.okHttp
151 | implementation libs.okHttpLoggingInterceptor
152 | implementation libs.retrofit
153 | implementation libs.retrofitGsonConverter
154 | implementation libs.retrofitRxJava2Adapter
155 |
156 | // PaperParcel
157 | implementation libs.paperParcel
158 | kapt proc.paperParcel
159 |
160 | // Timber
161 | implementation libs.timber
162 |
163 | // Stetho
164 | debugImplementation libs.stetho
165 |
166 | // LeakCanary
167 | debugImplementation libs.leakCanary
168 |
169 | // BlockCanary
170 | debugImplementation libs.blockCanary
171 |
172 | // Unit testing
173 | testImplementation test.junit
174 | testImplementation test.mockito
175 | testImplementation test.mockitoKotlin
176 | }
177 |
--------------------------------------------------------------------------------
/sectionsDecorator/src/main/java/co/netguru/sectionsDecorator/SectionDecorator.kt:
--------------------------------------------------------------------------------
1 | package co.netguru.sectionsDecorator
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Paint
6 | import android.graphics.Rect
7 | import android.support.annotation.ColorRes
8 | import android.support.annotation.LayoutRes
9 | import android.support.v7.widget.LinearLayoutManager
10 | import android.support.v7.widget.RecyclerView
11 | import android.view.LayoutInflater
12 | import android.view.View
13 | import android.view.ViewGroup
14 | import android.widget.LinearLayout
15 | import android.widget.TextView
16 |
17 |
18 | class SectionDecorator(private val context: Context) : RecyclerView.ItemDecoration() {
19 |
20 | private val headerVerticalOffset by lazy {
21 | context.resources.getDimensionPixelSize(R.dimen.header_vertical_offset).toFloat()
22 | }
23 | private val headerToLineOffset by lazy {
24 | context.resources.getDimensionPixelSize(R.dimen.header_to_line_offset).toFloat()
25 | }
26 | private val linePaint = Paint()
27 |
28 | private var headerView: TextView? = null
29 | private var headerLayoutId: Int = R.layout.section_header
30 |
31 | private var painter: Painter? = null
32 |
33 | init {
34 | linePaint.color = context.getColorCompat(android.R.color.black)
35 | linePaint.strokeWidth =
36 | context.resources.getDimensionPixelSize(R.dimen.divider_size).toFloat()
37 | }
38 |
39 | fun setLineColor(@ColorRes color: Int) {
40 | linePaint.color = context.getColorCompat(color)
41 | }
42 |
43 | fun setLineWidth(width: Float) {
44 | linePaint.strokeWidth = width
45 | }
46 |
47 | fun setHeaderView(@LayoutRes layout: Int) {
48 | headerView = null
49 | headerLayoutId = layout
50 | }
51 |
52 | override fun getItemOffsets(
53 | outRect: Rect,
54 | view: View,
55 | parent: RecyclerView,
56 | state: RecyclerView.State?
57 | ) {
58 | super.getItemOffsets(outRect, view, parent, state)
59 | createPainter(parent)
60 |
61 | painter?.getOutRect(outRect)
62 |
63 | }
64 |
65 | override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State?) {
66 | super.onDrawOver(canvas, parent, state)
67 | val adapter = getSectionsAdapter(parent)
68 |
69 | createPainter(parent)
70 |
71 | if (headerView == null) createHeaderView(parent)
72 |
73 | val sectionsList = parent.asSequence()
74 | .map {
75 | Pair(adapter.getSectionTitleForPosition(parent.getChildAdapterPosition(it)), it)
76 | }.fold(mapOf>()) { acc, data ->
77 | acc.addToValueList(data.first, data.second)
78 | }.toList()
79 |
80 | nullCheck2(painter, headerView) { painter, headerView ->
81 | sectionsList.forEachIndexed { index, (sectionTitle, sectionsVisibleElements) ->
82 | painter.paint(
83 | canvas,
84 | index,
85 | sectionTitle,
86 | sectionsVisibleElements,
87 | headerView,
88 | sectionsList.size,
89 | parent
90 | )
91 | }
92 | }
93 | }
94 |
95 | private fun getSectionsAdapter(parent: RecyclerView): SectionsAdapterInterface {
96 | return parent.adapter as SectionsAdapterInterface
97 | }
98 |
99 | private fun createHeaderView(parent: RecyclerView) {
100 | headerView = LayoutInflater.from(parent.context)
101 | .inflate(headerLayoutId, parent, false) as TextView
102 | fixLayoutSize(headerView!!, parent)
103 | }
104 |
105 | private fun createPainter(parent: RecyclerView) {
106 | if (painter == null) {
107 | if (parent.layoutManager !is LinearLayoutManager) {
108 | throw IllegalArgumentException("Section decorator only works with linear layout manager")
109 | } else {
110 | painter =
111 | if ((parent.layoutManager as LinearLayoutManager).orientation == LinearLayout.HORIZONTAL) {
112 | HorizontalPainter(::fixLayoutSize, headerToLineOffset, linePaint)
113 | } else {
114 | VerticalPainter(::fixLayoutSize, headerVerticalOffset, linePaint)
115 | }
116 | }
117 | }
118 | }
119 |
120 | private fun SectionsAdapterInterface.getSectionTitleForPosition(currentPosition: Int): String {
121 | var count = 0
122 | for (i in 0..getSectionsCount()) {
123 | count += getItemCountForSection(i)
124 | if (currentPosition < count) return getSectionTitleAt(i)
125 | }
126 | throw IndexOutOfBoundsException("try to get index=$currentPosition from items lenght=$count")
127 | }
128 |
129 | /**
130 | * Measures the headerTitle view to make sure its size is greater than 0 and will be drawn
131 | * [RecyclerView item decorations](https://yoda.entelect.co.za/view/9627/how-to-android-recyclerview-item-decorations)
132 | */
133 | private fun fixLayoutSize(view: View, parent: ViewGroup) {
134 | val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY)
135 | val heightSpec =
136 | View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)
137 |
138 | val childWidth = ViewGroup.getChildMeasureSpec(
139 | widthSpec, parent.paddingLeft + parent.paddingRight, view.layoutParams.width
140 | )
141 | val childHeight = ViewGroup.getChildMeasureSpec(
142 | heightSpec, parent.paddingTop + parent.paddingBottom, view.layoutParams.height
143 | )
144 |
145 | view.measure(childWidth, childHeight)
146 | view.layout(0, 0, view.measuredWidth, view.measuredHeight)
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/default-detekt-config.yml:
--------------------------------------------------------------------------------
1 | autoCorrect: true
2 | failFast: false
3 |
4 | test-pattern: # Configure exclusions for test sources
5 | active: true
6 | patterns: # Test file regexes
7 | - '.*/test/.*'
8 | - '.*Test.kt'
9 | - '.*Spec.kt'
10 | exclude-rule-sets:
11 | - 'comments'
12 | exclude-rules:
13 | - 'NamingRules'
14 | - 'WildcardImport'
15 | - 'MagicNumber'
16 | - 'MaxLineLength'
17 | - 'LateinitUsage'
18 | - 'StringLiteralDuplication'
19 | - 'SpreadOperator'
20 | - 'TooManyFunctions'
21 |
22 | build:
23 | warningThreshold: 50
24 | failThreshold: 1000
25 | weights:
26 | complexity: 2
27 | formatting: 1
28 | LongParameterList: 1
29 | comments: 1
30 |
31 | processors:
32 | active: true
33 | exclude:
34 | # - 'FunctionCountProcessor'
35 | # - 'PropertyCountProcessor'
36 | # - 'ClassCountProcessor'
37 | # - 'PackageCountProcessor'
38 | # - 'KtFileCountProcessor'
39 |
40 | console-reports:
41 | active: true
42 | exclude:
43 | # - 'ProjectStatisticsReport'
44 | # - 'ComplexityReport'
45 | # - 'NotificationReport'
46 | # - 'FindingsReport'
47 | # - 'BuildFailureReport'
48 |
49 | output-reports:
50 | active: true
51 | exclude:
52 | # - 'PlainOutputReport'
53 | # - 'XmlOutputReport'
54 |
55 | comments:
56 | active: true
57 | CommentOverPrivateFunction:
58 | active: false
59 | CommentOverPrivateProperty:
60 | active: false
61 | UndocumentedPublicClass:
62 | active: false
63 | searchInNestedClass: true
64 | searchInInnerClass: true
65 | searchInInnerObject: true
66 | searchInInnerInterface: true
67 | UndocumentedPublicFunction:
68 | active: false
69 |
70 | complexity:
71 | active: true
72 | LongParameterList:
73 | active: true
74 | threshold: 5
75 | ignoreDefaultParameters: false
76 | LongMethod:
77 | active: true
78 | threshold: 20
79 | LargeClass:
80 | active: true
81 | threshold: 150
82 | ComplexInterface:
83 | active: true
84 | threshold: 10
85 | includeStaticDeclarations: false
86 | ComplexMethod:
87 | active: true
88 | threshold: 10
89 | StringLiteralDuplication:
90 | active: true
91 | threshold: 2
92 | ignoreAnnotation: true
93 | excludeStringsWithLessThan5Characters: true
94 | ignoreStringsRegex: '$^'
95 | MethodOverloading:
96 | active: true
97 | threshold: 5
98 | NestedBlockDepth:
99 | active: true
100 | threshold: 3
101 | TooManyFunctions:
102 | active: true
103 | thresholdInFiles: 10
104 | thresholdInClasses: 10
105 | thresholdInInterfaces: 10
106 | thresholdInObjects: 10
107 | thresholdInEnums: 10
108 | ComplexCondition:
109 | active: true
110 | threshold: 3
111 | LabeledExpression:
112 | active: true
113 |
114 | empty-blocks:
115 | active: true
116 | EmptyCatchBlock:
117 | active: true
118 | EmptyClassBlock:
119 | active: true
120 | EmptyDefaultConstructor:
121 | active: true
122 | EmptyDoWhileBlock:
123 | active: true
124 | EmptyElseBlock:
125 | active: true
126 | EmptyFinallyBlock:
127 | active: true
128 | EmptyForBlock:
129 | active: true
130 | EmptyFunctionBlock:
131 | active: true
132 | EmptyIfBlock:
133 | active: true
134 | EmptyInitBlock:
135 | active: true
136 | EmptyKtFile:
137 | active: true
138 | EmptySecondaryConstructor:
139 | active: true
140 | EmptyWhenBlock:
141 | active: true
142 | EmptyWhileBlock:
143 | active: true
144 |
145 | exceptions:
146 | active: true
147 | TooGenericExceptionCaught:
148 | active: true
149 | exceptions:
150 | - ArrayIndexOutOfBoundsException
151 | - Error
152 | - Exception
153 | - IllegalMonitorStateException
154 | - NullPointerException
155 | - IndexOutOfBoundsException
156 | - RuntimeException
157 | - Throwable
158 | ExceptionRaisedInUnexpectedLocation:
159 | active: true
160 | methodNames: 'toString,hashCode,equals,finalize'
161 | TooGenericExceptionThrown:
162 | active: true
163 | exceptions:
164 | - Error
165 | - Exception
166 | - NullPointerException
167 | - Throwable
168 | - RuntimeException
169 | NotImplementedDeclaration:
170 | active: true
171 | PrintStackTrace:
172 | active: true
173 | InstanceOfCheckForException:
174 | active: true
175 | ThrowingExceptionsWithoutMessageOrCause:
176 | active: true
177 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException'
178 | ReturnFromFinally:
179 | active: true
180 | ThrowingExceptionFromFinally:
181 | active: true
182 | ThrowingExceptionInMain:
183 | active: false
184 | RethrowCaughtException:
185 | active: true
186 | ThrowingNewInstanceOfSameException:
187 | active: true
188 | SwallowedException:
189 | active: true
190 |
191 | performance:
192 | active: true
193 | ForEachOnRange:
194 | active: true
195 | SpreadOperator:
196 | active: true
197 | UnnecessaryTemporaryInstantiation:
198 | active: true
199 |
200 | potential-bugs:
201 | active: true
202 | DuplicateCaseInWhenExpression:
203 | active: true
204 | EqualsAlwaysReturnsTrueOrFalse:
205 | active: true
206 | EqualsWithHashCodeExist:
207 | active: true
208 | IteratorNotThrowingNoSuchElementException:
209 | active: true
210 | IteratorHasNextCallsNextMethod:
211 | active: true
212 | UselessPostfixExpression:
213 | active: true
214 | InvalidRange:
215 | active: true
216 | WrongEqualsTypeParameter:
217 | active: true
218 | ExplicitGarbageCollectionCall:
219 | active: true
220 | LateinitUsage:
221 | active: false
222 | excludeAnnotatedProperties: ""
223 | ignoreOnClassesPattern: ""
224 | UnconditionalJumpStatementInLoop:
225 | active: true
226 | UnreachableCode:
227 | active: true
228 | UnsafeCallOnNullableType:
229 | active: true
230 | UnsafeCast:
231 | active: true
232 |
233 | style:
234 | active: true
235 | CollapsibleIfStatements:
236 | active: true
237 | ReturnCount:
238 | active: true
239 | max: 2
240 | excludedFunctions: "equals"
241 | ThrowsCount:
242 | active: true
243 | max: 2
244 | NewLineAtEndOfFile:
245 | active: true
246 | WildcardImport:
247 | active: false
248 | excludeImports: 'java.util.*,kotlinx.android.synthetic.*'
249 | MaxLineLength:
250 | active: true
251 | maxLineLength: 120
252 | excludePackageStatements: false
253 | excludeImportStatements: false
254 | EqualsNullCall:
255 | active: true
256 | ForbiddenComment:
257 | active: true
258 | values: 'TODO:,FIXME:,STOPSHIP:'
259 | ForbiddenImport:
260 | active: false
261 | imports: ''
262 | FunctionOnlyReturningConstant:
263 | active: true
264 | ignoreOverridableFunction: true
265 | excludedFunctions: 'describeContents'
266 | SpacingBetweenPackageAndImports:
267 | active: true
268 | LoopWithTooManyJumpStatements:
269 | active: true
270 | maxJumpCount: 1
271 | MemberNameEqualsClassName:
272 | active: true
273 | ignoreOverriddenFunction: true
274 | VariableNaming:
275 | active: true
276 | variablePattern: '[a-z][A-Za-z0-9]*'
277 | privateVariablePattern: '[a-z][A-Za-z0-9]*'
278 | VariableMinLength:
279 | active: true
280 | minimumVariableNameLength: 1
281 | VariableMaxLength:
282 | active: false
283 | maximumVariableNameLength: 64
284 | TopLevelPropertyNaming:
285 | active: true
286 | constantPattern: '[A-Z][_A-Z0-9]*'
287 | propertyPattern: '[a-z][A-Za-z\d]*'
288 | privatePropertyPattern: '(_)?[a-z][A-Za-z0-9]*'
289 | ObjectPropertyNaming:
290 | active: true
291 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
292 | PackageNaming:
293 | active: true
294 | packagePattern: '^[a-z]+(\.[a-z][a-z0-9]*)*$'
295 | ClassNaming:
296 | active: true
297 | classPattern: '[A-Z$][a-zA-Z0-9$]*'
298 | EnumNaming:
299 | active: true
300 | enumEntryPattern: '^[A-Z$][a-zA-Z_$]*$'
301 | FunctionNaming:
302 | active: true
303 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$'
304 | FunctionMaxLength:
305 | active: true
306 | maximumFunctionNameLength: 30
307 | FunctionMinLength:
308 | active: false
309 | minimumFunctionNameLength: 3
310 | ForbiddenClassName:
311 | active: false
312 | forbiddenName: ''
313 | SafeCast:
314 | active: true
315 | UnnecessaryAbstractClass:
316 | active: true
317 | UnnecessaryParentheses:
318 | active: true
319 | UnnecessaryInheritance:
320 | active: true
321 | UtilityClassWithPublicConstructor:
322 | active: true
323 | OptionalAbstractKeyword:
324 | active: true
325 | OptionalWhenBraces:
326 | active: true
327 | OptionalReturnKeyword:
328 | active: false
329 | OptionalUnit:
330 | active: true
331 | ProtectedMemberInFinalClass:
332 | active: true
333 | SerialVersionUIDInSerializableClass:
334 | active: true
335 | MagicNumber:
336 | active: true
337 | ignoreNumbers: '-1,0,1,2'
338 | ignoreHashCodeFunction: false
339 | ignorePropertyDeclaration: false
340 | ignoreConstantDeclaration: true
341 | ignoreCompanionObjectPropertyDeclaration: true
342 | ignoreAnnotation: false
343 | ignoreNamedArgument: true
344 | ignoreEnums: false
345 | ModifierOrder:
346 | active: true
347 | DataClassContainsFunctions:
348 | active: true
349 | conversionFunctionPrefix: 'to'
350 | UseDataClass:
351 | active: true
352 | UnusedImports:
353 | active: true
354 | ExpressionBodySyntax:
355 | active: true
356 | NestedClassesVisibility:
357 | active: true
358 | RedundantVisibilityModifierRule:
359 | active: true
360 | MatchingDeclarationName:
361 | active: true
362 | UntilInsteadOfRangeTo:
363 | active: true
364 |
--------------------------------------------------------------------------------