From bda83d074576b05db599717bf8205ff356b35ea0 Mon Sep 17 00:00:00 2001 From: Vahid Garousi Date: Fri, 27 Jan 2023 18:41:16 +0330 Subject: [PATCH 1/5] Adding Detekt for #43 --- build.gradle | 2 + buildscripts/detekt.gradle | 14 + config/detekt/detekt.yml | 723 +++++++++++++++++++++++++++++++++++++ 3 files changed, 739 insertions(+) create mode 100644 buildscripts/detekt.gradle create mode 100644 config/detekt/detekt.yml diff --git a/build.gradle b/build.gradle index 676960a..4098ff8 100644 --- a/build.gradle +++ b/build.gradle @@ -10,9 +10,11 @@ plugins { id 'com.google.dagger.hilt.android' version '2.44.2' apply false id "com.github.ben-manes.versions" version "0.44.0" id "com.diffplug.spotless" version "6.12.1" + id "io.gitlab.arturbosch.detekt" version "1.22.0" } subprojects { apply from: "../buildscripts/versionsplugin.gradle" apply from: "../buildscripts/spotless.gradle" + apply from: "../buildscripts/detekt.gradle" } \ No newline at end of file diff --git a/buildscripts/detekt.gradle b/buildscripts/detekt.gradle new file mode 100644 index 0000000..72908a8 --- /dev/null +++ b/buildscripts/detekt.gradle @@ -0,0 +1,14 @@ +apply plugin: "io.gitlab.arturbosch.detekt" + +detekt { + config = files("${rootProject.rootDir}/config/detekt/detekt.yml") +} + + +tasks.named("detekt").configure { + reports { + html.enabled = true + xml.enabled = true + txt.enabled = true + } +} \ No newline at end of file diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 0000000..df3db53 --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,723 @@ +build: + maxIssues: 0 + excludeCorrectable: false + weights: + # complexity: 2 + # LongParameterList: 1 + # style: 1 + # comments: 1 + +config: + validation: true + warningsAsErrors: false + checkExhaustiveness: false + # when writing own rules with new properties, exclude the property path e.g.: 'my_rule_set,.*>.*>[my_property]' + excludes: '' + +processors: + active: true + exclude: + - 'DetektProgressListener' + # - 'KtFileCountProcessor' + # - 'PackageCountProcessor' + # - 'ClassCountProcessor' + # - 'FunctionCountProcessor' + # - 'PropertyCountProcessor' + # - 'ProjectComplexityProcessor' + # - 'ProjectCognitiveComplexityProcessor' + # - 'ProjectLLOCProcessor' + # - 'ProjectCLOCProcessor' + # - 'ProjectLOCProcessor' + # - 'ProjectSLOCProcessor' + # - 'LicenseHeaderLoaderExtension' + +console-reports: + active: true + exclude: + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + - 'FindingsReport' + - 'FileBasedFindingsReport' + # - 'LiteFindingsReport' + +output-reports: + active: true + exclude: + # - 'TxtOutputReport' + # - 'XmlOutputReport' + # - 'HtmlOutputReport' + # - 'MdOutputReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + licenseTemplateFile: 'license.template' + licenseTemplateIsRegex: false + CommentOverPrivateFunction: + active: false + CommentOverPrivateProperty: + active: false + DeprecatedBlockTag: + active: false + EndOfSentenceFormat: + active: false + endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' + KDocReferencesNonPublicProperty: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + OutdatedDocumentation: + active: false + matchTypeParameters: true + matchDeclarationsOrder: true + allowParamOnConstructorProperties: false + UndocumentedPublicClass: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + searchInNestedClass: true + searchInInnerClass: true + searchInInnerObject: true + searchInInnerInterface: true + searchInProtectedClass: false + UndocumentedPublicFunction: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + searchProtectedFunction: false + UndocumentedPublicProperty: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + searchProtectedProperty: false + +complexity: + active: true + CognitiveComplexMethod: + active: false + threshold: 15 + ComplexCondition: + active: true + threshold: 4 + ComplexInterface: + active: false + threshold: 10 + includeStaticDeclarations: false + includePrivateDeclarations: false + ignoreOverloaded: false + CyclomaticComplexMethod: + active: true + threshold: 15 + ignoreSingleWhenExpression: false + ignoreSimpleWhenEntries: false + ignoreNestingFunctions: false + nestingFunctions: + - 'also' + - 'apply' + - 'forEach' + - 'isNotNull' + - 'ifNull' + - 'let' + - 'run' + - 'use' + - 'with' + LabeledExpression: + active: false + ignoredLabels: [] + LargeClass: + active: true + threshold: 600 + LongMethod: + active: true + threshold: 60 + LongParameterList: + active: true + functionThreshold: 6 + constructorThreshold: 7 + ignoreDefaultParameters: false + ignoreDataClasses: true + ignoreAnnotatedParameter: [] + MethodOverloading: + active: false + threshold: 6 + NamedArguments: + active: true + threshold: 3 + ignoreArgumentsMatchingNames: false + NestedBlockDepth: + active: true + threshold: 4 + NestedScopeFunctions: + active: false + threshold: 1 + functions: + - 'kotlin.apply' + - 'kotlin.run' + - 'kotlin.with' + - 'kotlin.let' + - 'kotlin.also' + ReplaceSafeCallChainWithRun: + active: false + StringLiteralDuplication: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + threshold: 3 + ignoreAnnotation: true + excludeStringsWithLessThan5Characters: true + ignoreStringsRegex: '$^' + TooManyFunctions: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + thresholdInFiles: 11 + thresholdInClasses: 11 + thresholdInInterfaces: 11 + thresholdInObjects: 11 + thresholdInEnums: 11 + ignoreDeprecated: false + ignorePrivate: false + ignoreOverridden: false + +coroutines: + active: true + GlobalCoroutineUsage: + active: false + InjectDispatcher: + active: true + dispatcherNames: + - 'IO' + - 'Default' + - 'Unconfined' + RedundantSuspendModifier: + active: true + SleepInsteadOfDelay: + active: true + SuspendFunWithCoroutineScopeReceiver: + active: false + SuspendFunWithFlowReturnType: + active: true + +empty-blocks: + active: true + EmptyCatchBlock: + active: true + allowedExceptionNameRegex: '_|(ignore|expected).*' + EmptyClassBlock: + active: true + EmptyDefaultConstructor: + active: true + EmptyDoWhileBlock: + active: true + EmptyElseBlock: + active: true + EmptyFinallyBlock: + active: true + EmptyForBlock: + active: true + EmptyFunctionBlock: + active: true + ignoreOverridden: false + EmptyIfBlock: + active: true + EmptyInitBlock: + active: true + EmptyKtFile: + active: true + EmptySecondaryConstructor: + active: true + EmptyTryBlock: + active: true + EmptyWhenBlock: + active: true + EmptyWhileBlock: + active: true + +exceptions: + active: true + ExceptionRaisedInUnexpectedLocation: + active: true + methodNames: + - 'equals' + - 'finalize' + - 'hashCode' + - 'toString' + InstanceOfCheckForException: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + NotImplementedDeclaration: + active: false + ObjectExtendsThrowable: + active: false + PrintStackTrace: + active: true + RethrowCaughtException: + active: true + ReturnFromFinally: + active: true + ignoreLabeled: false + SwallowedException: + active: true + ignoredExceptionTypes: + - 'InterruptedException' + - 'MalformedURLException' + - 'NumberFormatException' + - 'ParseException' + allowedExceptionNameRegex: '_|(ignore|expected).*' + ThrowingExceptionFromFinally: + active: true + ThrowingExceptionInMain: + active: false + ThrowingExceptionsWithoutMessageOrCause: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptions: + - 'ArrayIndexOutOfBoundsException' + - 'Exception' + - 'IllegalArgumentException' + - 'IllegalMonitorStateException' + - 'IllegalStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + ThrowingNewInstanceOfSameException: + active: true + TooGenericExceptionCaught: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + exceptionNames: + - 'ArrayIndexOutOfBoundsException' + - 'Error' + - 'Exception' + - 'IllegalMonitorStateException' + - 'IndexOutOfBoundsException' + - 'NullPointerException' + - 'RuntimeException' + - 'Throwable' + allowedExceptionNameRegex: '_|(ignore|expected).*' + TooGenericExceptionThrown: + active: true + exceptionNames: + - 'Error' + - 'Exception' + - 'RuntimeException' + - 'Throwable' + +naming: + active: true + BooleanPropertyNaming: + active: false + allowedPattern: '^(is|has|are)' + ignoreOverridden: true + ClassNaming: + active: true + classPattern: '[A-Z][a-zA-Z0-9]*' + ConstructorParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + privateParameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + EnumNaming: + active: true + enumEntryPattern: '[A-Z][_a-zA-Z0-9]*' + ForbiddenClassName: + active: false + forbiddenName: [] + FunctionMaxLength: + active: false + maximumFunctionNameLength: 30 + FunctionMinLength: + active: false + minimumFunctionNameLength: 3 + FunctionNaming: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + functionPattern: '[a-z][a-zA-Z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + FunctionParameterNaming: + active: true + parameterPattern: '[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + InvalidPackageDeclaration: + active: true + rootPackage: '' + requireRootInDeclaration: false + LambdaParameterNaming: + active: false + parameterPattern: '[a-z][A-Za-z0-9]*|_' + MatchingDeclarationName: + active: true + mustBeFirst: true + MemberNameEqualsClassName: + active: true + ignoreOverridden: true + NoNameShadowing: + active: true + NonBooleanPropertyPrefixedWithIs: + active: false + ObjectPropertyNaming: + active: true + constantPattern: '[A-Za-z][_A-Za-z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' + PackageNaming: + active: true + packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' + TopLevelPropertyNaming: + active: true + constantPattern: '[A-Z][_A-Z0-9]*' + propertyPattern: '[A-Za-z][_A-Za-z0-9]*' + privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' + VariableMaxLength: + active: false + maximumVariableNameLength: 64 + VariableMinLength: + active: false + minimumVariableNameLength: 1 + VariableNaming: + active: true + variablePattern: '[a-z][A-Za-z0-9]*' + privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' + excludeClassPattern: '$^' + ignoreOverridden: true + +performance: + active: true + ArrayPrimitive: + active: true + CouldBeSequence: + active: false + threshold: 3 + ForEachOnRange: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + SpreadOperator: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + UnnecessaryPartOfBinaryExpression: + active: false + UnnecessaryTemporaryInstantiation: + active: true + +potential-bugs: + active: true + AvoidReferentialEquality: + active: true + forbiddenTypePatterns: + - 'kotlin.String' + CastToNullableType: + active: false + Deprecation: + active: false + DontDowncastCollectionTypes: + active: false + DoubleMutabilityForCollection: + active: true + mutableTypes: + - 'kotlin.collections.MutableList' + - 'kotlin.collections.MutableMap' + - 'kotlin.collections.MutableSet' + - 'java.util.ArrayList' + - 'java.util.LinkedHashSet' + - 'java.util.HashSet' + - 'java.util.LinkedHashMap' + - 'java.util.HashMap' + ElseCaseInsteadOfExhaustiveWhen: + active: false + EqualsAlwaysReturnsTrueOrFalse: + active: true + EqualsWithHashCodeExist: + active: true + ExitOutsideMain: + active: false + ExplicitGarbageCollectionCall: + active: true + HasPlatformType: + active: true + IgnoredReturnValue: + active: true + restrictToConfig: true + returnValueAnnotations: + - '*.CheckResult' + - '*.CheckReturnValue' + ignoreReturnValueAnnotations: + - '*.CanIgnoreReturnValue' + returnValueTypes: + - 'kotlin.sequences.Sequence' + - 'kotlinx.coroutines.flow.*Flow' + - 'java.util.stream.*Stream' + ignoreFunctionCall: [] + ImplicitDefaultLocale: + active: true + ImplicitUnitReturnType: + active: false + allowExplicitReturnType: true + InvalidRange: + active: true + IteratorHasNextCallsNextMethod: + active: true + IteratorNotThrowingNoSuchElementException: + active: true + LateinitUsage: + active: false + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + ignoreOnClassesPattern: '' + MapGetWithNotNullAssertionOperator: + active: true + MissingPackageDeclaration: + active: false + excludes: ['**/*.kts'] + NullCheckOnMutableProperty: + active: false + NullableToStringCall: + active: false + UnconditionalJumpStatementInLoop: + active: false + UnnecessaryNotNullCheck: + active: false + UnnecessaryNotNullOperator: + active: true + UnnecessarySafeCall: + active: true + UnreachableCatchBlock: + active: true + UnreachableCode: + active: true + UnsafeCallOnNullableType: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**'] + UnsafeCast: + active: true + UnusedUnaryOperator: + active: true + UselessPostfixExpression: + active: true + WrongEqualsTypeParameter: + active: true + +style: + active: true + AlsoCouldBeApply: + active: false + CanBeNonNullable: + active: false + CascadingCallWrapping: + active: false + includeElvis: true + ClassOrdering: + active: false + CollapsibleIfStatements: + active: false + DataClassContainsFunctions: + active: false + conversionFunctionPrefix: + - 'to' + DataClassShouldBeImmutable: + active: false + DestructuringDeclarationWithTooManyEntries: + active: true + maxDestructuringEntries: 3 + EqualsNullCall: + active: true + EqualsOnSignatureLine: + active: false + ExplicitCollectionElementAccessMethod: + active: false + ExplicitItLambdaParameter: + active: true + ExpressionBodySyntax: + active: false + includeLineWrapping: false + ForbiddenComment: + active: true + values: + - 'FIXME:' + - 'STOPSHIP:' + - 'TODO:' + allowedPatterns: '' + customMessage: '' + ForbiddenImport: + active: false + imports: [] + forbiddenPatterns: '' + ForbiddenMethodCall: + active: false + methods: + - reason: 'print does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.print' + - reason: 'println does not allow you to configure the output stream. Use a logger instead.' + value: 'kotlin.io.println' + ForbiddenSuppress: + active: false + rules: [] + ForbiddenVoid: + active: true + ignoreOverridden: false + ignoreUsageInGenerics: false + FunctionOnlyReturningConstant: + active: true + ignoreOverridableFunction: true + ignoreActualFunction: true + excludedFunctions: [] + LoopWithTooManyJumpStatements: + active: true + maxJumpCount: 1 + MagicNumber: + active: true + excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts'] + ignoreNumbers: + - '-1' + - '0' + - '1' + - '2' + ignoreHashCodeFunction: true + ignorePropertyDeclaration: false + ignoreLocalVariableDeclaration: false + ignoreConstantDeclaration: true + ignoreCompanionObjectPropertyDeclaration: true + ignoreAnnotation: false + ignoreNamedArgument: true + ignoreEnums: false + ignoreRanges: false + ignoreExtensionFunctions: true + MandatoryBracesIfStatements: + active: false + MandatoryBracesLoops: + active: false + MaxChainedCallsOnSameLine: + active: false + maxChainedCalls: 5 + MaxLineLength: + active: true + maxLineLength: 120 + excludePackageStatements: true + excludeImportStatements: true + excludeCommentStatements: false + excludeRawStrings: true + MayBeConst: + active: true + ModifierOrder: + active: true + MultilineLambdaItParameter: + active: false + MultilineRawStringIndentation: + active: false + indentSize: 4 + NestedClassesVisibility: + active: true + NewLineAtEndOfFile: + active: true + NoTabs: + active: false + NullableBooleanCheck: + active: false + ObjectLiteralToLambda: + active: true + OptionalAbstractKeyword: + active: true + OptionalUnit: + active: false + OptionalWhenBraces: + active: false + PreferToOverPairSyntax: + active: false + ProtectedMemberInFinalClass: + active: true + RedundantExplicitType: + active: false + RedundantHigherOrderMapUsage: + active: true + RedundantVisibilityModifierRule: + active: false + ReturnCount: + active: true + max: 2 + excludedFunctions: + - 'equals' + excludeLabeled: false + excludeReturnFromLambda: true + excludeGuardClauses: false + SafeCast: + active: true + SerialVersionUIDInSerializableClass: + active: true + SpacingBetweenPackageAndImports: + active: false + ThrowsCount: + active: true + max: 2 + excludeGuardClauses: false + TrailingWhitespace: + active: false + TrimMultilineRawString: + active: false + UnderscoresInNumericLiterals: + active: false + acceptableLength: 4 + allowNonStandardGrouping: false + UnnecessaryAbstractClass: + active: true + UnnecessaryAnnotationUseSiteTarget: + active: false + UnnecessaryApply: + active: true + UnnecessaryBackticks: + active: false + UnnecessaryFilter: + active: true + UnnecessaryInheritance: + active: true + UnnecessaryInnerClass: + active: false + UnnecessaryLet: + active: false + UnnecessaryParentheses: + active: false + allowForUnclearPrecedence: false + UntilInsteadOfRangeTo: + active: false + UnusedImports: + active: false + UnusedPrivateClass: + active: true + UnusedPrivateMember: + active: true + allowedNames: '(_|ignored|expected|serialVersionUID)' + UseAnyOrNoneInsteadOfFind: + active: true + UseArrayLiteralsInAnnotations: + active: true + UseCheckNotNull: + active: true + UseCheckOrError: + active: true + UseDataClass: + active: false + allowVars: false + UseEmptyCounterpart: + active: false + UseIfEmptyOrIfBlank: + active: false + UseIfInsteadOfWhen: + active: false + UseIsNullOrEmpty: + active: true + UseOrEmpty: + active: true + UseRequire: + active: true + UseRequireNotNull: + active: true + UseSumOfInsteadOfFlatMapSize: + active: false + UselessCallOnNotNull: + active: true + UtilityClassWithPublicConstructor: + active: true + VarCouldBeVal: + active: true + ignoreLateinitVar: false + WildcardImport: + active: true + excludeImports: + - 'java.util.*' From 03e2fdafde37ad8c76f76b02752babef5c0fda77 Mon Sep 17 00:00:00 2001 From: Vahid Garousi Date: Fri, 27 Jan 2023 18:46:02 +0330 Subject: [PATCH 2/5] Running detekt on actions. --- .github/workflows/android_build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 072d1e7..2c295a0 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -21,4 +21,7 @@ jobs: run: chmod +x ./gradlew - name: Build Project - run: ./gradlew assemble \ No newline at end of file + run: ./gradlew assemble + + - name: Static Analysis + run: ./gradlew ktlintCheck detekt \ No newline at end of file From 40d3f415cc229109592f5e04e6fd655e2f8ebffc Mon Sep 17 00:00:00 2001 From: Vahid Garousi Date: Fri, 27 Jan 2023 18:52:27 +0330 Subject: [PATCH 3/5] Running spotlessCheck on actions. --- .github/workflows/android_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 2c295a0..0488908 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -24,4 +24,4 @@ jobs: run: ./gradlew assemble - name: Static Analysis - run: ./gradlew ktlintCheck detekt \ No newline at end of file + run: ./gradlew spotlessCheck detekt \ No newline at end of file From 6ac906cd689e545d4858cb6ba636b3f8f2456533 Mon Sep 17 00:00:00 2001 From: Vahid Garousi Date: Fri, 27 Jan 2023 20:50:11 +0330 Subject: [PATCH 4/5] Fixing detekt issues --- .../data/EmptySubscriptionListener.kt | 1 + .../watchlist/data/LightStreamerConnection.kt | 2 ++ .../feature/watchlist/data/StatefulData.kt | 28 +++++++++++++------ .../watchlist/data/SubscriptionMode.kt | 1 + .../watchlist/di/LightStreamerModule.kt | 2 ++ .../watchlist/di/StockRepositoryModule.kt | 1 + .../watchlist/presentation/StockItem.kt | 7 ++++- .../watchlist/presentation/StockList.kt | 1 + .../watchlist/presentation/WatchlistScreen.kt | 25 ++--------------- .../watchlist/presentation/WatchlistState.kt | 1 + .../presentation/WatchlistViewModel.kt | 7 +++-- .../navigation/JankStatsExtensions.kt | 1 + .../navigation/StockWatcherNavHost.kt | 2 +- .../stockwatcher/ui/StockWatcherApp.kt | 10 ++----- .../stockwatcher/ui/StockWatcherAppState.kt | 1 + .../garousi/stockwatcher/ui/theme/Color.kt | 1 + .../garousi/stockwatcher/ui/theme/Theme.kt | 1 + config/detekt/detekt.yml | 2 +- 18 files changed, 49 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/EmptySubscriptionListener.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/EmptySubscriptionListener.kt index 1f7869c..8ab1e05 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/EmptySubscriptionListener.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/EmptySubscriptionListener.kt @@ -1,3 +1,4 @@ +@file:Suppress("TooManyFunctions") package dev.garousi.stockwatcher.feature.watchlist.data import com.lightstreamer.client.ItemUpdate diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt index 19b0b9c..bed5d5e 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt @@ -1,3 +1,5 @@ +@file:Suppress("LongParameterList","TooManyFunctions") + package dev.garousi.stockwatcher.feature.watchlist.data import android.util.Log diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/StatefulData.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/StatefulData.kt index e79805d..da99a0d 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/StatefulData.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/StatefulData.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.transform + sealed class StatefulData { data class Success(val result: T) : StatefulData() data class Error(val msg: String) : StatefulData() @@ -35,14 +36,23 @@ fun Flow.wrapWithStatefulData(): Flow> = transform return@transform emit(StatefulData.Success(value)) } -inline fun Flow>.mapState(crossinline transform: suspend (value: T) -> R): Flow> = transform { value -> - return@transform emit(value.suspendMap(transform)) -} +inline fun Flow>.mapState( + crossinline transform: suspend (value: T) -> R +): Flow> = + transform { value -> + return@transform emit(value.suspendMap(transform)) + } -inline fun Flow>.onSuccessState(crossinline action: suspend (value: T) -> Unit): Flow> = onEach { - if (it is StatefulData.Success) action(it.result) -} +inline fun Flow>.onSuccessState( + crossinline action: suspend (value: T) -> Unit +): Flow> = + onEach { + if (it is StatefulData.Success) action(it.result) + } -inline fun Flow>.onErrorState(crossinline action: suspend (error: String) -> Unit): Flow> = onEach { - if (it is StatefulData.Error) action(it.msg) -} +inline fun Flow>.onErrorState( + crossinline action: suspend (error: String) -> Unit +): Flow> = + onEach { + if (it is StatefulData.Error) action(it.msg) + } diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt index 1114eeb..892c7aa 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt @@ -1,3 +1,4 @@ +@file:Suppress("UnusedPrivateMember") package dev.garousi.stockwatcher.feature.watchlist.data enum class SubscriptionMode(mode: String) { diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/LightStreamerModule.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/LightStreamerModule.kt index 3407ab4..47af65d 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/LightStreamerModule.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/LightStreamerModule.kt @@ -1,3 +1,5 @@ +@file:Suppress("UnnecessaryAbstractClass") + package dev.garousi.stockwatcher.feature.watchlist.di import dagger.Binds diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/StockRepositoryModule.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/StockRepositoryModule.kt index 2fd4184..b91e9df 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/StockRepositoryModule.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/di/StockRepositoryModule.kt @@ -1,3 +1,4 @@ +@file:Suppress("UnnecessaryAbstractClass") package dev.garousi.stockwatcher.feature.watchlist.di import dagger.Binds diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockItem.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockItem.kt index da7f5ef..ede4e6c 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockItem.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockItem.kt @@ -1,3 +1,5 @@ +@file:Suppress("MagicNumber", "LongMethod", "FunctionNaming", "CyclomaticComplexMethod") + package dev.garousi.stockwatcher.feature.watchlist.presentation import androidx.compose.foundation.layout.Arrangement @@ -159,7 +161,10 @@ fun StockItem( textAlign = TextAlign.Center, ) Icon( - imageVector = if (stock.change > 0) Icons.Filled.KeyboardArrowUp else Icons.Filled.KeyboardArrowDown, + imageVector = if (stock.change > 0) + Icons.Filled.KeyboardArrowUp + else + Icons.Filled.KeyboardArrowDown, contentDescription = null, tint = if (stock.change > 0) Color(0XFF48BE62) else Color(0XFFBE4848), modifier = Modifier diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt index 720f9f1..ece98d0 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt @@ -1,3 +1,4 @@ +@file:Suppress("FunctionNaming") package dev.garousi.stockwatcher.feature.watchlist.presentation import androidx.compose.foundation.Image diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt index cf6e1a3..0321239 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt @@ -1,3 +1,5 @@ +@file:Suppress("FunctionNaming", "LongParameterList") + package dev.garousi.stockwatcher.feature.watchlist.presentation import androidx.compose.animation.AnimatedVisibility @@ -130,26 +132,3 @@ private fun WatchlistTopAppBar( ) } } - -@Composable -private fun LoadingView() { - Box( - modifier = Modifier.fillMaxSize(), - ) { - CircularProgressIndicator( - modifier = Modifier.align(Alignment.Center), - ) - } -} - -@Composable -private fun ErrorView() { - Box( - modifier = Modifier.fillMaxSize(), - ) { - Text( - text = "Error Happened", - modifier = Modifier.align(Alignment.Center), - ) - } -} diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt index 1353e67..05cbd6b 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt @@ -1,3 +1,4 @@ +@file:Suppress("MagicNumber","ForEachOnRange") package dev.garousi.stockwatcher.feature.watchlist.presentation import dev.garousi.stockwatcher.feature.watchlist.domain.models.Stock diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistViewModel.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistViewModel.kt index 7ce8e1c..16adeca 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistViewModel.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistViewModel.kt @@ -1,3 +1,4 @@ +@file:Suppress("CyclomaticComplexMethod") package dev.garousi.stockwatcher.feature.watchlist.presentation import android.util.Log @@ -32,9 +33,6 @@ class WatchlistViewModel @Inject constructor( stockListLightStreamerService .subscribe() .flow - .catch { cause: Throwable -> - Log.i("LOGGER", "" + cause.localizedMessage.orEmpty()) - } .map { stock -> _uiState.update { it.copy(isLoading = false) } stock.itemPos?.let { updatedItemIndex -> @@ -60,6 +58,9 @@ class WatchlistViewModel @Inject constructor( } } } + .catch { cause: Throwable -> + Log.i("LOGGER", "" + cause.localizedMessage.orEmpty()) + } .stateIn( scope = viewModelScope, initialValue = StockListDto(), diff --git a/app/src/main/java/dev/garousi/stockwatcher/navigation/JankStatsExtensions.kt b/app/src/main/java/dev/garousi/stockwatcher/navigation/JankStatsExtensions.kt index 4079ce1..85a5be4 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/navigation/JankStatsExtensions.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/navigation/JankStatsExtensions.kt @@ -1,3 +1,4 @@ +@file:Suppress("FunctionNaming") /* * Copyright 2022 The Android Open Source Project * diff --git a/app/src/main/java/dev/garousi/stockwatcher/navigation/StockWatcherNavHost.kt b/app/src/main/java/dev/garousi/stockwatcher/navigation/StockWatcherNavHost.kt index c3e60a2..4ca67a0 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/navigation/StockWatcherNavHost.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/navigation/StockWatcherNavHost.kt @@ -1,3 +1,4 @@ +@file:Suppress("FunctionNaming") package dev.garousi.stockwatcher.navigation import androidx.compose.runtime.Composable @@ -8,7 +9,6 @@ import androidx.navigation.compose.NavHost @Composable fun StockWatcherNavHost( navController: NavHostController, - onBackClick: () -> Unit, modifier: Modifier = Modifier, startDestination: String = watchlistGraphRoutePattern, ) { diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt index a233ac3..41d22c0 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt @@ -1,3 +1,4 @@ +@file:Suppress("FunctionNaming") package dev.garousi.stockwatcher.ui import androidx.compose.foundation.layout.Column @@ -32,8 +33,7 @@ fun StockWatcherApp( testTagsAsResourceId = true }, bottomBar = { - if (appState.shouldShowBottomBar) { - } + }, ) { padding -> Row( @@ -49,12 +49,8 @@ fun StockWatcherApp( ) { Column(Modifier.fillMaxSize()) { // Show the top app bar on top level destinations. - val destination = appState.currentTopLevelDestination - if (destination != null) { - } StockWatcherNavHost( - navController = appState.navController, - onBackClick = appState::onBackClick, + navController = appState.navController ) } } diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherAppState.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherAppState.kt index 6134c91..715e329 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherAppState.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherAppState.kt @@ -1,3 +1,4 @@ +@file:Suppress("FunctionNaming") package dev.garousi.stockwatcher.ui import androidx.compose.runtime.Composable diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Color.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Color.kt index d2e813a..594e1e8 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Color.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Color.kt @@ -1,3 +1,4 @@ +@file:Suppress("MagicNumber") package dev.garousi.stockwatcher.ui.theme import androidx.compose.ui.graphics.Color diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt index 1482006..d147fed 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt @@ -1,3 +1,4 @@ +@file:Suppress("MagicNumber","FunctionNaming") package dev.garousi.stockwatcher.ui.theme import androidx.compose.foundation.isSystemInDarkTheme diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index df3db53..3bfc618 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -364,7 +364,7 @@ naming: active: true packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*' TopLevelPropertyNaming: - active: true + active: false constantPattern: '[A-Z][_A-Z0-9]*' propertyPattern: '[A-Za-z][_A-Za-z0-9]*' privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' From d5f06968eb401babcb929fd25e6cbb2e1ffda1d6 Mon Sep 17 00:00:00 2001 From: Vahid Garousi Date: Fri, 27 Jan 2023 21:29:58 +0330 Subject: [PATCH 5/5] Replacing Spotless with Ktlint --- .github/workflows/android_build.yml | 2 +- .../watchlist/data/LightStreamerConnection.kt | 2 +- .../feature/watchlist/data/SubscriptionMode.kt | 6 +++--- .../feature/watchlist/presentation/StockList.kt | 2 +- .../watchlist/presentation/WatchlistScreen.kt | 1 - .../watchlist/presentation/WatchlistState.kt | 2 +- .../dev/garousi/stockwatcher/ui/StockWatcherApp.kt | 1 - .../dev/garousi/stockwatcher/ui/theme/Theme.kt | 2 +- build.gradle | 7 ++++--- buildscripts/ktlint.gradle | 14 ++++++++++++++ 10 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 buildscripts/ktlint.gradle diff --git a/.github/workflows/android_build.yml b/.github/workflows/android_build.yml index 0488908..2c295a0 100644 --- a/.github/workflows/android_build.yml +++ b/.github/workflows/android_build.yml @@ -24,4 +24,4 @@ jobs: run: ./gradlew assemble - name: Static Analysis - run: ./gradlew spotlessCheck detekt \ No newline at end of file + run: ./gradlew ktlintCheck detekt \ No newline at end of file diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt index bed5d5e..26738ae 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/LightStreamerConnection.kt @@ -1,4 +1,4 @@ -@file:Suppress("LongParameterList","TooManyFunctions") +@file:Suppress("LongParameterList", "TooManyFunctions") package dev.garousi.stockwatcher.feature.watchlist.data diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt index 892c7aa..ce6e560 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/data/SubscriptionMode.kt @@ -1,7 +1,7 @@ @file:Suppress("UnusedPrivateMember") package dev.garousi.stockwatcher.feature.watchlist.data -enum class SubscriptionMode(mode: String) { - Merge("MERGE"), - Command("COMMAND"), +enum class SubscriptionMode { + Merge, + Command, } diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt index ece98d0..09fdf98 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/StockList.kt @@ -41,7 +41,7 @@ fun StockList( ) { itemsIndexed( items = stocks, - key = { index, item -> item.itemName }, + key = { _, item -> item.itemName }, ) { index, stock -> StockItem( stock = stock, diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt index 0321239..9e053de 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistScreen.kt @@ -28,7 +28,6 @@ import androidx.compose.material.primarySurface import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.Center import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier diff --git a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt index 05cbd6b..520e108 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/feature/watchlist/presentation/WatchlistState.kt @@ -1,4 +1,4 @@ -@file:Suppress("MagicNumber","ForEachOnRange") +@file:Suppress("MagicNumber", "ForEachOnRange") package dev.garousi.stockwatcher.feature.watchlist.presentation import dev.garousi.stockwatcher.feature.watchlist.domain.models.Stock diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt index 41d22c0..3a5941f 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/StockWatcherApp.kt @@ -33,7 +33,6 @@ fun StockWatcherApp( testTagsAsResourceId = true }, bottomBar = { - }, ) { padding -> Row( diff --git a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt index d147fed..4edd93d 100644 --- a/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt +++ b/app/src/main/java/dev/garousi/stockwatcher/ui/theme/Theme.kt @@ -1,4 +1,4 @@ -@file:Suppress("MagicNumber","FunctionNaming") +@file:Suppress("MagicNumber", "FunctionNaming") package dev.garousi.stockwatcher.ui.theme import androidx.compose.foundation.isSystemInDarkTheme diff --git a/build.gradle b/build.gradle index 4098ff8..df828ac 100644 --- a/build.gradle +++ b/build.gradle @@ -9,12 +9,13 @@ plugins { id 'org.jetbrains.kotlin.android' version '1.7.20' apply false id 'com.google.dagger.hilt.android' version '2.44.2' apply false id "com.github.ben-manes.versions" version "0.44.0" - id "com.diffplug.spotless" version "6.12.1" +// id "com.diffplug.spotless" version "6.12.1" id "io.gitlab.arturbosch.detekt" version "1.22.0" + id "org.jlleitschuh.gradle.ktlint" version "10.2.0" } subprojects { - apply from: "../buildscripts/versionsplugin.gradle" - apply from: "../buildscripts/spotless.gradle" + apply from: "../buildscripts/ktlint.gradle" apply from: "../buildscripts/detekt.gradle" + apply from: "../buildscripts/versionsplugin.gradle" } \ No newline at end of file diff --git a/buildscripts/ktlint.gradle b/buildscripts/ktlint.gradle new file mode 100644 index 0000000..c706b57 --- /dev/null +++ b/buildscripts/ktlint.gradle @@ -0,0 +1,14 @@ +apply plugin: "org.jlleitschuh.gradle.ktlint" + +ktlint { + // https://github.com/pinterest/ktlint/releases + version = "0.45.2" + + reporters { + reporter "plain" + reporter "checkstyle" + reporter "html" + } + + outputColorName = "RED" +} \ No newline at end of file