diff --git a/build-logic/plugins/build.gradle.kts b/build-logic/plugins/build.gradle.kts index a9b74157b..9f3741a12 100644 --- a/build-logic/plugins/build.gradle.kts +++ b/build-logic/plugins/build.gradle.kts @@ -25,6 +25,7 @@ tasks.withType().configureEach { dependencies { compileOnly(libs.android.gradle.api) + compileOnly(libs.detekt.gradle.plugin) compileOnly(libs.kotlinx.kover.gradle) compileOnly(libs.kotlin.gradle.plugin) @@ -69,5 +70,10 @@ gradlePlugin { id = "ch.srgssr.pillarbox.gradle.android_library_tested_module" implementationClass = "ch.srgssr.pillarbox.gradle.PillarboxAndroidLibraryTestedModulePlugin" } + + register("PillarboxDetekt") { + id = "ch.srgssr.pillarbox.gradle.detekt" + implementationClass = "ch.srgssr.pillarbox.gradle.PillarboxDetektPlugin" + } } } diff --git a/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/PillarboxDetektPlugin.kt b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/PillarboxDetektPlugin.kt new file mode 100644 index 000000000..a6f6a97a8 --- /dev/null +++ b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/PillarboxDetektPlugin.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) SRG SSR. All rights reserved. + * License information is available from the LICENSE file. + */ +package ch.srgssr.pillarbox.gradle + +import ch.srgssr.pillarbox.gradle.internal.AppConfig +import ch.srgssr.pillarbox.gradle.internal.libs +import io.gitlab.arturbosch.detekt.Detekt +import io.gitlab.arturbosch.detekt.extensions.DetektExtension +import io.gitlab.arturbosch.detekt.report.ReportMergeTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType + +/** + * Custom Gradle plugin to configure Detekt for Pillarbox. + * + * Check [Detekt's documentation](https://detekt.dev/docs/gettingstarted/gradle) for more information. + */ +class PillarboxDetektPlugin : Plugin { + override fun apply(target: Project) = with(target) { + pluginManager.apply("android-reporting") + + val detektReportMerge = tasks.register("detektReportMerge") { + output.set(rootProject.layout.buildDirectory.file("reports/detekt/pillarbox-android.sarif")) + } + + allprojects { + pluginManager.apply("io.gitlab.arturbosch.detekt") + + val detektTasks = tasks.withType() + + detektTasks.configureEach { + jvmTarget = AppConfig.javaVersionName + + reports { + html.required.set(true) + md.required.set(false) + sarif.required.set(true) + txt.required.set(false) + xml.required.set(false) + } + + finalizedBy(detektReportMerge) + } + + extensions.configure { + autoCorrect = true + basePath = rootDir.absolutePath + buildUponDefaultConfig = true + config.setFrom(rootProject.layout.projectDirectory.file("config/detekt/detekt.yml")) + ignoredBuildTypes = listOf("release") + parallel = true + } + + detektReportMerge.configure { + input.from(detektTasks.map { it.sarifReportFile }) + } + + dependencies.add("detekt", libs.findLibrary("detekt-cli").get()) + dependencies.add("detektPlugins", libs.findLibrary("detekt-formatting").get()) + } + } +} diff --git a/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/AppConfig.kt b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/AppConfig.kt index 615d9f9b4..05e5a7887 100644 --- a/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/AppConfig.kt +++ b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/AppConfig.kt @@ -8,13 +8,11 @@ import org.gradle.api.JavaVersion import org.jetbrains.kotlin.gradle.dsl.JvmTarget internal object AppConfig { - // When changing this value, don't forget to also update the Detekt config in the root `build.gradle.kts` file - private val javaVersionName = "17" - internal const val minSdk = 21 internal const val targetSdk = 34 internal const val compileSdk = 34 + internal const val javaVersionName = "17" internal val javaVersion = JavaVersion.valueOf("VERSION_$javaVersionName") internal val jvmTarget = JvmTarget.fromTarget(javaVersionName) } diff --git a/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/ProjectExtensions.kt b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/ProjectExtensions.kt index 4008e942a..ea57ad27d 100644 --- a/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/ProjectExtensions.kt +++ b/build-logic/plugins/src/main/java/ch/srgssr/pillarbox/gradle/internal/ProjectExtensions.kt @@ -6,9 +6,15 @@ package ch.srgssr.pillarbox.gradle.internal import com.android.build.api.dsl.CommonExtension import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +internal val Project.libs: VersionCatalog + get() = extensions.getByType().named("libs") + internal fun Project.configureAndroidModule(extension: CommonExtension<*, *, *, *, *, *>) = with(extension) { namespace = "ch.srgssr.pillarbox." + name.removePrefix("pillarbox-").replace('-', '.') compileSdk = AppConfig.compileSdk diff --git a/build.gradle.kts b/build.gradle.kts index 111b29d94..e2a8e295b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,8 +2,6 @@ * Copyright (c) SRG SSR. All rights reserved. * License information is available from the LICENSE file. */ -import io.gitlab.arturbosch.detekt.Detekt -import io.gitlab.arturbosch.detekt.report.ReportMergeTask // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { @@ -16,57 +14,16 @@ plugins { alias(libs.plugins.dependency.analysis.gradle.plugin) alias(libs.plugins.dokka) apply false alias(libs.plugins.kotlinx.kover) + alias(libs.plugins.pillarbox.detekt) } -apply(plugin = "android-reporting") - -val detektReportMerge by tasks.registering(ReportMergeTask::class) { - output.set(rootProject.layout.buildDirectory.file("reports/detekt/pillarbox-android.sarif")) -} - -allprojects { - apply(plugin = "io.gitlab.arturbosch.detekt") - // Official site : https://detekt.dev/docs/gettingstarted/gradle - // Tutorial : https://medium.com/@nagendran.p/integrating-detekt-in-the-android-studio-442128e971f8 - detekt { - config.setFrom(files("../config/detekt/detekt.yml")) - // preconfigure defaults - buildUponDefaultConfig = false - ignoredBuildTypes = listOf("release") - autoCorrect = true - parallel = true - } - - dependencies { - detekt(libs.detekt.cli) - detektPlugins(libs.detekt.formatting) - } - - tasks.withType().configureEach { - jvmTarget = JavaVersion.VERSION_17.majorVersion - basePath = rootDir.absolutePath - reports { - xml.required = false - html.required = true - txt.required = false - sarif.required = true - md.required = false - } - finalizedBy(detektReportMerge) - } - - detektReportMerge { - input.from(tasks.withType().map { it.sarifReportFile }) - } -} - -// Configure the `wrapper` task, so it can be easily be updated by simply running `./gradlew wrapper`. +// Configure the `wrapper` task, so it can easily be updated by simply running `./gradlew wrapper`. tasks.wrapper { distributionType = Wrapper.DistributionType.ALL gradleVersion = "latest" } -tasks.register("clean") { +val clean by tasks.registering(Delete::class) { delete(rootProject.layout.buildDirectory) } @@ -74,7 +31,7 @@ tasks.register("clean") { * https://detekt.dev/docs/gettingstarted/git-pre-commit-hook * https://medium.com/@alistair.cerio/android-ktlint-and-pre-commit-git-hook-5dd606e230a9 */ -tasks.register("installGitHook") { +val installGitHook by tasks.registering(Copy::class) { description = "Install the Git pre-commit hook locally" from(file("${rootProject.rootDir}/git_hooks/pre-commit")) into { file("${rootProject.rootDir}/.git/hooks") } @@ -83,7 +40,7 @@ tasks.register("installGitHook") { } } -tasks.getByPath(":pillarbox-demo:preBuild").dependsOn(":installGitHook") +tasks.getByPath(":pillarbox-demo:preBuild").dependsOn(installGitHook) dependencyAnalysis { issues { diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 1c690a2aa..0853e8412 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -1,870 +1,53 @@ # Official doc at https://detekt.dev/docs/rules/style#libraryentitiesshouldnotbepublic -build: - maxIssues: 0 - excludeCorrectable: false - weights: - # complexity: 2 - # LongParameterList: 1 - # style: 1 - # comments: 1 - -config: - validation: true - warningsAsErrors: 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: true - EndOfSentenceFormat: - active: false - endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)' - KDocReferencesNonPublicProperty: - active: false - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - OutdatedDocumentation: - active: true - matchTypeParameters: true - matchDeclarationsOrder: true - allowParamOnConstructorProperties: false - UndocumentedPublicClass: - active: true - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - searchInNestedClass: true - searchInInnerClass: true - searchInInnerObject: true - searchInInnerInterface: true - UndocumentedPublicFunction: - active: true - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - ignoreAnnotated: [ 'Preview' ] - UndocumentedPublicProperty: - active: true - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] complexity: - active: true - ComplexCondition: - active: true - threshold: 4 - ComplexInterface: - active: true - threshold: 10 - includeStaticDeclarations: false - includePrivateDeclarations: 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: false - threshold: 600 + LongMethod: active: false - threshold: 60 - ignoreAnnotated: [ 'Composable' ] + LongParameterList: - active: false functionThreshold: 10 - constructorThreshold: 7 + ignoreAnnotated: [ 'Composable' ] ignoreDefaultParameters: true - ignoreDataClasses: true - ignoreAnnotatedParameter: [ ] - MethodOverloading: - active: false - threshold: 6 - NamedArguments: - active: true - threshold: 3 - ignoreArgumentsMatchingNames: false - NestedBlockDepth: - active: true - threshold: 4 - NestedScopeFunctions: - active: true - threshold: 1 - functions: - - 'kotlin.apply' - - 'kotlin.run' - - 'kotlin.with' - - 'kotlin.let' - - 'kotlin.also' - ReplaceSafeCallChainWithRun: - active: true - StringLiteralDuplication: - active: true - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - threshold: 3 - ignoreAnnotation: true - excludeStringsWithLessThan5Characters: true - ignoreStringsRegex: '$^' + TooManyFunctions: - active: false - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - thresholdInFiles: 11 - thresholdInClasses: 11 - thresholdInInterfaces: 11 - thresholdInObjects: 11 - thresholdInEnums: 11 - ignoreDeprecated: false - ignorePrivate: false + ignoreAnnotatedFunctions: [ 'Composable', 'Preview', 'PreviewLightDark' ] ignoreOverridden: true - -coroutines: - active: true - GlobalCoroutineUsage: - active: true - InjectDispatcher: - active: true - dispatcherNames: - - 'IO' - - 'Default' - - 'Unconfined' - RedundantSuspendModifier: - active: true - SleepInsteadOfDelay: - active: true - SuspendFunWithCoroutineScopeReceiver: - active: false - SuspendFunWithFlowReturnType: - active: true + ignorePrivate: 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: true - 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: +formatting: + ArgumentListWrapping: + maxLineLength: 150 + + CommentWrapping: 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' + + MaximumLineLength: + maxLineLength: 150 + + PropertyWrapping: + maxLineLength: 150 naming: - active: true - BooleanPropertyNaming: - active: false - allowedPattern: '^(is|has|are)' - 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: '$^' - 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: '$^' ignoreAnnotated: [ 'Composable' ] - FunctionParameterNaming: - active: true - parameterPattern: '[a-z][A-Za-z0-9]*' - excludeClassPattern: '$^' - 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-Za-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: '$^' - -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/**' ] - UnnecessaryTemporaryInstantiation: - active: true - -potential-bugs: - active: true - AvoidReferentialEquality: - active: true - forbiddenTypePatterns: - - 'kotlin.String' - CastToNullableType: - active: false - Deprecation: - active: false - DontDowncastCollectionTypes: - active: true - 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: false - returnValueAnnotations: - - '*.CheckResult' - - '*.CheckReturnValue' - ignoreReturnValueAnnotations: - - '*.CanIgnoreReturnValue' - 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 - 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 - CanBeNonNullable: - active: false - CascadingCallWrapping: - active: true - includeElvis: true - ClassOrdering: - active: true - CollapsibleIfStatements: - active: true - 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 - comments: - - 'FIXME:' - - 'STOPSHIP:' - - 'TODO:' - allowedPatterns: '' - ForbiddenImport: - active: false - imports: [ ] - forbiddenPatterns: '' - ForbiddenMethodCall: - active: false - methods: - - 'kotlin.io.print' - - '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: true - ignoreLocalVariableDeclaration: false - ignoreConstantDeclaration: true - ignoreCompanionObjectPropertyDeclaration: true - ignoreAnnotation: false - ignoreNamedArgument: true - ignoreEnums: false - ignoreRanges: false - ignoreExtensionFunctions: true ignoreAnnotated: [ 'Composable' ] - BracesOnIfStatements: - active: false - MandatoryBracesLoops: - active: false - MaxChainedCallsOnSameLine: - active: false - maxChainedCalls: 5 + ignorePropertyDeclaration: true + MaxLineLength: - active: true maxLineLength: 150 - excludePackageStatements: true - excludeImportStatements: true - excludeCommentStatements: false - MayBeConst: - active: true - ModifierOrder: - active: true - MultilineLambdaItParameter: - active: false - NestedClassesVisibility: - active: true - NewLineAtEndOfFile: - active: true - NoTabs: - active: false - NullableBooleanCheck: - active: false - ObjectLiteralToLambda: - active: true - OptionalAbstractKeyword: - active: true - OptionalUnit: - active: false - BracesOnWhenStatements: - 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 - 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 - UntilInsteadOfRangeTo: - active: false - UnusedImports: - active: false - UnusedPrivateClass: - active: true + UnusedPrivateMember: - active: true - allowedNames: '(_|ignored|expected|serialVersionUID)' ignoreAnnotated: [ 'Preview', 'PreviewLightDark' ] - 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 - UselessCallOnNotNull: - active: true - UtilityClassWithPublicConstructor: - active: true - VarCouldBeVal: - active: true - ignoreLateinitVar: false - WildcardImport: - active: true - excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/iosTest/**' ] - excludeImports: - - 'java.util.*' - -formatting: - active: true - android: false - autoCorrect: true - AnnotationOnSeparateLine: - active: false - autoCorrect: true - AnnotationSpacing: - active: false - autoCorrect: true - ArgumentListWrapping: - active: false - autoCorrect: true - indentSize: 4 - maxLineLength: 120 - BlockCommentInitialStarAlignment: - active: false - autoCorrect: true - ChainWrapping: - active: true - autoCorrect: true - CommentSpacing: - active: true - autoCorrect: true - CommentWrapping: - active: false - autoCorrect: true - indentSize: 4 - DiscouragedCommentLocation: - active: false - autoCorrect: true - EnumEntryNameCase: - active: false - autoCorrect: true - Filename: - active: true - FinalNewline: - active: true - autoCorrect: true - insertFinalNewLine: true - FunKeywordSpacing: - active: false - autoCorrect: true - FunctionTypeReferenceSpacing: - active: false - autoCorrect: true - ImportOrdering: - active: true - autoCorrect: true - layout: '*,java.**,javax.**,kotlin.**,^' - Indentation: - active: true - autoCorrect: true - indentSize: 4 - KdocWrapping: - active: false - autoCorrect: true - indentSize: 4 - MaximumLineLength: - active: true - maxLineLength: 150 - ignoreBackTickedIdentifier: false - ModifierListSpacing: - active: false - autoCorrect: true - ModifierOrdering: - active: true - autoCorrect: true - MultiLineIfElse: - active: false - autoCorrect: true - NoBlankLineBeforeRbrace: - active: true - autoCorrect: true - NoConsecutiveBlankLines: - active: true - autoCorrect: true - NoEmptyClassBody: - active: true - autoCorrect: true - NoEmptyFirstLineInMethodBlock: - active: false - autoCorrect: true - NoLineBreakAfterElse: - active: true - autoCorrect: true - NoLineBreakBeforeAssignment: - active: true - autoCorrect: true - NoMultipleSpaces: - active: true - autoCorrect: true - NoSemicolons: - active: true - autoCorrect: true - NoTrailingSpaces: - active: true - autoCorrect: true - NoUnitReturn: - active: true - autoCorrect: true - NoUnusedImports: - active: true - autoCorrect: true - NoWildcardImports: - active: true - packagesToUseImportOnDemandProperty: 'java.util.*,kotlinx.android.synthetic.**' - PackageName: - active: false - autoCorrect: true - ParameterListWrapping: - active: true - autoCorrect: true - maxLineLength: 120 - SpacingAroundAngleBrackets: - active: false - autoCorrect: true - SpacingAroundColon: - active: true - autoCorrect: true - SpacingAroundComma: - active: true - autoCorrect: true - SpacingAroundCurly: - active: true - autoCorrect: true - SpacingAroundDot: - active: true - autoCorrect: true - SpacingAroundDoubleColon: - active: false - autoCorrect: true - SpacingAroundKeyword: - active: true - autoCorrect: true - SpacingAroundOperators: - active: true - autoCorrect: true - SpacingAroundParens: - active: true - autoCorrect: true - SpacingAroundRangeOperator: - active: true - autoCorrect: true - SpacingAroundUnaryOperator: - active: false - autoCorrect: true - SpacingBetweenDeclarationsWithAnnotations: - active: false - autoCorrect: true - SpacingBetweenDeclarationsWithComments: - active: false - autoCorrect: true - StringTemplate: - active: true - autoCorrect: true - - TypeArgumentListSpacing: - active: false - autoCorrect: true - UnnecessaryParenthesesBeforeTrailingLambda: - active: false - autoCorrect: true - Wrapping: - active: true - autoCorrect: true - - TrailingCommaOnCallSite: - active: false - autoCorrect: true - useTrailingCommaOnCallSite: false - TrailingCommaOnDeclarationSite: - active: false - autoCorrect: true - useTrailingCommaOnDeclarationSite: false - diff --git a/gradle.properties b/gradle.properties index ba013361f..6ff36ff0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,3 +28,6 @@ org.gradle.configuration-cache=false # Print dependency analysis report to the console dependency.analysis.print.build.health=true + +# Let Detekt use Gradle's Worker API (https://detekt.dev/docs/gettingstarted/gradle/#options-for-detekt-gradle-properties) +detekt.use.worker.api=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index da5233345..5207bb65d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,6 +85,7 @@ srg-dataprovider-paging = { module = "ch.srg.data.provider:dataprovider-paging", srg-dataprovider-retrofit = { module = "ch.srg.data.provider:dataprovider-retrofit", version.ref = "srg-data-provider" } detekt-cli = { group = "io.gitlab.arturbosch.detekt", name = "detekt-cli", version.ref = "detekt" } detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } +detekt-gradle-plugin = { group = "io.gitlab.arturbosch.detekt", name = "io.gitlab.arturbosch.detekt.gradle.plugin", version.ref = "detekt" } junit = { group = "junit", name = "junit", version.ref = "junit" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } mockk-dsl = { group = "io.mockk", name = "mockk-dsl-jvm", version.ref = "mockk" } @@ -143,9 +144,10 @@ kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version. kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlinx-kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kotlinx-kover" } -pillarbox-android-application = { id = "ch.srgssr.pillarbox.gradle.android_application", version = "unspecified" } -pillarbox-android-library = { id = "ch.srgssr.pillarbox.gradle.android_library", version = "unspecified" } -pillarbox-android-library-compose = { id = "ch.srgssr.pillarbox.gradle.android_library_compose", version = "unspecified" } -pillarbox-android-library-lint = { id = "ch.srgssr.pillarbox.gradle.android_library_lint", version = "unspecified" } -pillarbox-android-library-publishing = { id = "ch.srgssr.pillarbox.gradle.android_library_publishing", version = "unspecified" } -pillarbox-android-library-tested-module = { id = "ch.srgssr.pillarbox.gradle.android_library_tested_module", version = "unspecified" } +pillarbox-android-application = { id = "ch.srgssr.pillarbox.gradle.android_application" } +pillarbox-android-library = { id = "ch.srgssr.pillarbox.gradle.android_library" } +pillarbox-android-library-compose = { id = "ch.srgssr.pillarbox.gradle.android_library_compose" } +pillarbox-android-library-lint = { id = "ch.srgssr.pillarbox.gradle.android_library_lint" } +pillarbox-android-library-publishing = { id = "ch.srgssr.pillarbox.gradle.android_library_publishing" } +pillarbox-android-library-tested-module = { id = "ch.srgssr.pillarbox.gradle.android_library_tested_module" } +pillarbox-detekt = { id = "ch.srgssr.pillarbox.gradle.detekt" } diff --git a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/ChapterAdapterTest.kt b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/ChapterAdapterTest.kt index 5be17683a..ba670aa96 100644 --- a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/ChapterAdapterTest.kt +++ b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/ChapterAdapterTest.kt @@ -82,9 +82,7 @@ class ChapterAdapterTest { imageUrl = "https://www.rts.ch/image.png", mediaType = MediaType.VIDEO, ) - val mediaComposition = MediaComposition( - chapterUrn = mainChapter.urn, listChapter = listOf(mainChapter) - ) + val mediaComposition = MediaComposition(chapterUrn = mainChapter.urn, listChapter = listOf(mainChapter)) assertEquals(emptyList(), ChapterAdapter.getChapters(mediaComposition)) } @@ -100,9 +98,7 @@ class ChapterAdapterTest { ) val chapter1 = fullLengthChapter.copy(urn = "urn:chapter1") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter2") - val mediaComposition = MediaComposition( - chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2)) assertEquals(emptyList(), ChapterAdapter.getChapters(mediaComposition)) } @@ -118,9 +114,7 @@ class ChapterAdapterTest { ) val chapter1 = mainChapter.copy(urn = "urn:chapter1", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = mainChapter.copy(urn = "urn:chapter2", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "urn") - val mediaComposition = MediaComposition( - chapterUrn = mainChapter.urn, listChapter = listOf(mainChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = mainChapter.urn, listChapter = listOf(mainChapter, chapter1, chapter2)) val expected = listOf(ChapterAdapter.toChapter(chapter1), ChapterAdapter.toChapter(chapter2)) assertEquals(expected, ChapterAdapter.getChapters(mediaComposition)) } @@ -137,9 +131,7 @@ class ChapterAdapterTest { ) val chapter1 = fullLengthChapter.copy(urn = "urn:chapter1", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter2", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "urn") - val mediaComposition = MediaComposition( - chapterUrn = "urn:chapter1", listChapter = listOf(fullLengthChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = "urn:chapter1", listChapter = listOf(fullLengthChapter, chapter1, chapter2)) assertEquals(emptyList(), ChapterAdapter.getChapters(mediaComposition)) } @@ -155,9 +147,7 @@ class ChapterAdapterTest { ) val chapter1 = fullLengthChapter.copy(urn = "urn:chapter1", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter2", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "urn") - val mediaComposition = MediaComposition( - chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2)) assertEquals(emptyList(), ChapterAdapter.getChapters(mediaComposition)) } @@ -173,9 +163,7 @@ class ChapterAdapterTest { ) val chapter1 = fullLengthChapter.copy(urn = "urn:chapter", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") - val mediaComposition = MediaComposition( - chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2)) assertEquals(emptyList(), ChapterAdapter.getChapters(mediaComposition)) } @@ -192,11 +180,13 @@ class ChapterAdapterTest { val chapter1 = fullLengthChapter.copy(urn = "urn:chapter1", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter2", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "urn") val chapter3 = fullLengthChapter.copy( - urn = "urn:chapter3", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "urn", mediaType = MediaType.AUDIO - ) - val mediaComposition = MediaComposition( - chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2, chapter3) + urn = "urn:chapter3", + fullLengthMarkIn = 30, + fullLengthMarkOut = 60, + fullLengthUrn = "urn", + mediaType = MediaType.AUDIO ) + val mediaComposition = MediaComposition(chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2, chapter3)) assertEquals( listOf(chapter1, chapter2).map { ChapterAdapter.toChapter(it) @@ -217,9 +207,7 @@ class ChapterAdapterTest { ) val chapter1 = fullLengthChapter.copy(urn = "urn:chapter1", fullLengthMarkIn = 0, fullLengthMarkOut = 10, fullLengthUrn = "urn") val chapter2 = fullLengthChapter.copy(urn = "urn:chapter2", fullLengthMarkIn = 30, fullLengthMarkOut = 60, fullLengthUrn = "other urn") - val mediaComposition = MediaComposition( - chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2) - ) + val mediaComposition = MediaComposition(chapterUrn = "urn", listChapter = listOf(fullLengthChapter, chapter1, chapter2)) assertEquals(listOf(chapter1).map { ChapterAdapter.toChapter(it) }, ChapterAdapter.getChapters(mediaComposition)) } } diff --git a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt index e5bfcd058..d27fd4311 100644 --- a/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt +++ b/pillarbox-core-business/src/test/java/ch/srgssr/pillarbox/core/business/SRGAssetLoaderTest.kt @@ -171,11 +171,7 @@ class SRGAssetLoaderTest { URN_NO_RESOURCES -> Result.success(createMediaComposition(urn, null)) URN_EMPTY_RESOURCES -> Result.success(createMediaComposition(urn, emptyList())) URN_HLS_RESOURCE -> Result.success(createMediaComposition(urn, listOf(createResource(Resource.Type.HLS)))) - URN_INCOMPATIBLE_RESOURCE -> Result.success( - createMediaComposition( - urn, listOf(createResource(Resource.Type.UNKNOWN)) - ) - ) + URN_INCOMPATIBLE_RESOURCE -> Result.success(createMediaComposition(urn, listOf(createResource(Resource.Type.UNKNOWN)))) URN_METADATA -> { val chapter = Chapter( diff --git a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/integrationLayer/data/ILRepository.kt b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/integrationLayer/data/ILRepository.kt index 88f3a5670..11b51701f 100644 --- a/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/integrationLayer/data/ILRepository.kt +++ b/pillarbox-demo-shared/src/main/java/ch/srgssr/pillarbox/demo/shared/ui/integrationLayer/data/ILRepository.kt @@ -2,6 +2,8 @@ * Copyright (c) SRG SSR. All rights reserved. * License information is available from the LICENSE file. */ +@file:Suppress("TooManyFunctions") + package ch.srgssr.pillarbox.demo.shared.ui.integrationLayer.data import androidx.paging.Pager @@ -187,7 +189,8 @@ class ILRepository( */ fun search(bu: Bu, query: String): Flow> { return dataProviderPaging.searchMedia( - bu = bu, searchTerm = query, + bu = bu, + searchTerm = query, queryParameters = SearchParams.MediaParams(includeAggregations = false), pageSize = PAGE_SIZE ) diff --git a/pillarbox-demo-tv/src/main/java/ch/srgssr/pillarbox/demo/tv/ui/player/compose/MediaMetadataView.kt b/pillarbox-demo-tv/src/main/java/ch/srgssr/pillarbox/demo/tv/ui/player/compose/MediaMetadataView.kt index e523e99e7..92cec5c4b 100644 --- a/pillarbox-demo-tv/src/main/java/ch/srgssr/pillarbox/demo/tv/ui/player/compose/MediaMetadataView.kt +++ b/pillarbox-demo-tv/src/main/java/ch/srgssr/pillarbox/demo/tv/ui/player/compose/MediaMetadataView.kt @@ -98,7 +98,11 @@ private fun MediaMetadataPreview() { val mediaMetadata = MediaMetadata.Builder() .setTitle("Title") .setDescription("Description") - .setArtworkUri(Uri.parse("https://cdn.prod.swi-services.ch/video-delivery/images/14e4562f-725d-4e41-a200-7fcaa77df2fe/5rwf1Bq_m3GC5secOZcIcgbbrbZPf4nI/16x9)")) + .setArtworkUri( + Uri.parse( + "https://cdn.prod.swi-services.ch/video-delivery/images/14e4562f-725d-4e41-a200-7fcaa77df2fe/5rwf1Bq_m3GC5secOZcIcgbbrbZPf4nI/16x9)" + ) + ) .build() MediaMetadataView( diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/MainNavigation.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/MainNavigation.kt index c2bedf8ba..67c0013dc 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/MainNavigation.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/MainNavigation.kt @@ -73,11 +73,13 @@ import java.net.URL private val bottomNavItems = listOf(HomeDestination.Examples, HomeDestination.ShowCases, HomeDestination.Lists, HomeDestination.Search, HomeDestination.Settings) -private val topLevelRoutes = - listOf( - HomeDestination.Examples.route, NavigationRoutes.showcaseList, NavigationRoutes.contentLists, HomeDestination.Search.route, - HomeDestination.Settings.route - ) +private val topLevelRoutes = listOf( + HomeDestination.Examples.route, + NavigationRoutes.showcaseList, + NavigationRoutes.contentLists, + HomeDestination.Search.route, + HomeDestination.Settings.route +) /** * Main view with all the navigation diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerBottomToolbar.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerBottomToolbar.kt index 28419c3fe..ec324e5e0 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerBottomToolbar.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerBottomToolbar.kt @@ -41,7 +41,8 @@ fun PlayerBottomToolbar( IconButton(onClick = it) { Icon( tint = Color.White, - imageVector = Icons.Default.PictureInPicture, contentDescription = "Picture in picture" + imageVector = Icons.Default.PictureInPicture, + contentDescription = "Picture in picture" ) } } @@ -50,12 +51,14 @@ fun PlayerBottomToolbar( if (fullScreenEnabled) { Icon( tint = Color.White, - imageVector = Icons.Default.FullscreenExit, contentDescription = "Exit full screen" + imageVector = Icons.Default.FullscreenExit, + contentDescription = "Exit full screen" ) } else { Icon( tint = Color.White, - imageVector = Icons.Default.Fullscreen, contentDescription = "Open in full screen" + imageVector = Icons.Default.Fullscreen, + contentDescription = "Open in full screen" ) } } @@ -66,7 +69,8 @@ fun PlayerBottomToolbar( ) { Icon( tint = Color.White, - imageVector = Icons.Default.Settings, contentDescription = stringResource(R.string.settings) + imageVector = Icons.Default.Settings, + contentDescription = stringResource(R.string.settings) ) } } diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerPlaybackRow.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerPlaybackRow.kt index 47b756a5c..b276e0aa8 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerPlaybackRow.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerPlaybackRow.kt @@ -98,7 +98,8 @@ private fun Button( ) { IconButton(modifier = modifier, onClick = onClick, enabled = isEnabled) { Icon( - imageVector = icon, contentDescription = contentDescription, + imageVector = icon, + contentDescription = contentDescription, tint = if (isEnabled) Color.White else Color.LightGray, ) } diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerTimeSlider.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerTimeSlider.kt index fe7cc946e..2cac94cda 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerTimeSlider.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/player/controls/PlayerTimeSlider.kt @@ -79,8 +79,7 @@ fun PlayerTimeSlider( val rememberedProgressTracker by rememberUpdatedState(progressTracker) val durationMs by player.durationAsState() val duration = remember(durationMs) { - if (durationMs == C.TIME_UNSET) ZERO - else durationMs.milliseconds + if (durationMs == C.TIME_UNSET) ZERO else durationMs.milliseconds } val currentProgress by rememberedProgressTracker.progress.collectAsState() val currentProgressPercent = currentProgress.inWholeMilliseconds / player.duration.coerceAtLeast(1).toFloat() diff --git a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/layouts/ChapterShowcase.kt b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/layouts/ChapterShowcase.kt index 5d0e9b69a..993a55f90 100644 --- a/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/layouts/ChapterShowcase.kt +++ b/pillarbox-demo/src/main/java/ch/srgssr/pillarbox/demo/ui/showcases/layouts/ChapterShowcase.kt @@ -116,7 +116,9 @@ private fun ChapterList( ChapterItem( modifier = Modifier .aspectRatio(16 / 9f), - chapter = chapter, active = currentChapter == chapter, onClick = { onChapterClick(chapter) } + chapter = chapter, + active = currentChapter == chapter, + onClick = { onChapterClick(chapter) } ) } } @@ -175,8 +177,10 @@ private fun ChapterItemPreview() { .fillMaxWidth() .aspectRatio(16 / 9f), chapter = Chapter( - "i1", 5.minutes.inWholeMilliseconds, 12.minutes.inWholeMilliseconds, - MediaMetadata.Builder() + id = "i1", + start = 5.minutes.inWholeMilliseconds, + end = 12.minutes.inWholeMilliseconds, + mediaMetadata = MediaMetadata.Builder() .setTitle("Title2") .setArtworkUri( Uri.parse( diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PlayerCallbackFlow.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PlayerCallbackFlow.kt index 96268ab2c..5583d38f7 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PlayerCallbackFlow.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/PlayerCallbackFlow.kt @@ -2,6 +2,8 @@ * Copyright (c) SRG SSR. All rights reserved. * License information is available from the LICENSE file. */ +@file:Suppress("TooManyFunctions") + package ch.srgssr.pillarbox.player import androidx.media3.common.C diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/analytics/PillarboxAnalyticsCollector.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/analytics/PillarboxAnalyticsCollector.kt index 50efc8833..910951650 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/analytics/PillarboxAnalyticsCollector.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/analytics/PillarboxAnalyticsCollector.kt @@ -40,52 +40,54 @@ class PillarboxAnalyticsCollector( override fun onStallChanged(isStall: Boolean) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_STALL_CHANGED) { listener -> listener.onStallChanged(eventTime, isStall) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_STALL_CHANGED) { listener -> + listener.onStallChanged(eventTime, isStall) + } } override fun onSmoothSeekingEnabledChanged(smoothSeekingEnabled: Boolean) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox( - eventTime, PillarboxAnalyticsListener.EVENT_SMOOTH_SEEKING_ENABLED_CHANGED - ) { listener -> listener.onSmoothSeekingEnabledChanged(eventTime, smoothSeekingEnabled) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_SMOOTH_SEEKING_ENABLED_CHANGED) { listener -> + listener.onSmoothSeekingEnabledChanged(eventTime, smoothSeekingEnabled) + } } override fun onTrackingEnabledChanged(trackingEnabled: Boolean) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox( - eventTime, PillarboxAnalyticsListener.EVENT_TRACKING_ENABLED_CHANGED - ) { listener -> listener.onTrackingEnabledChanged(eventTime, trackingEnabled) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_TRACKING_ENABLED_CHANGED) { listener -> + listener.onTrackingEnabledChanged(eventTime, trackingEnabled) + } } override fun onChapterChanged(chapter: Chapter?) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox( - eventTime, PillarboxAnalyticsListener.EVENT_CHAPTER_CHANGED - ) { listener -> listener.onChapterChanged(eventTime, chapter) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_CHAPTER_CHANGED) { listener -> + listener.onChapterChanged(eventTime, chapter) + } } override fun onCreditChanged(credit: Credit?) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox( - eventTime, PillarboxAnalyticsListener.EVENT_CREDIT_CHANGED - ) { listener -> listener.onCreditChanged(eventTime, credit) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_CREDIT_CHANGED) { listener -> + listener.onCreditChanged(eventTime, credit) + } } override fun onBlockedTimeRangeReached(blockedTimeRange: BlockedTimeRange) { val eventTime = generateCurrentPlayerMediaPeriodEventTime() - sendEventPillarbox( - eventTime, PillarboxAnalyticsListener.EVENT_BLOCKED_TIME_RANGE_REACHED - ) { listener -> listener.onBlockedTimeRangeReached(eventTime, blockedTimeRange) } + sendEventPillarbox(eventTime, PillarboxAnalyticsListener.EVENT_BLOCKED_TIME_RANGE_REACHED) { listener -> + listener.onBlockedTimeRangeReached(eventTime, blockedTimeRange) + } } private fun sendEventPillarbox(eventTime: EventTime, eventFlag: Int, event: Event) { - sendEvent( - eventTime, eventFlag - ) { listener -> if (listener is PillarboxAnalyticsListener) event.invoke(listener) } + sendEvent(eventTime, eventFlag) { listener -> + if (listener is PillarboxAnalyticsListener) event.invoke(listener) + } } } diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/extension/TrackSelectionParameters.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/extension/TrackSelectionParameters.kt index 574afbd83..852a780af 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/extension/TrackSelectionParameters.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/extension/TrackSelectionParameters.kt @@ -2,6 +2,8 @@ * Copyright (c) SRG SSR. All rights reserved. * License information is available from the LICENSE file. */ +@file:Suppress("TooManyFunctions") + package ch.srgssr.pillarbox.player.extension import android.content.Context diff --git a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/session/PillarboxMediaController.kt b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/session/PillarboxMediaController.kt index cd189d05e..7f939ba2f 100644 --- a/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/session/PillarboxMediaController.kt +++ b/pillarbox-player/src/main/java/ch/srgssr/pillarbox/player/session/PillarboxMediaController.kt @@ -313,7 +313,8 @@ open class PillarboxMediaController internal constructor() : PillarboxPlayer { if (resultSession.resultCode != SessionResult.RESULT_SUCCESS) { DebugLogger.warning(TAG, "SessionResult ${command.customAction} code ${resultSession.resultCode}") } - }, MoreExecutors.directExecutor() + }, + MoreExecutors.directExecutor() ) return result } diff --git a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/FakeAssetLoader.kt b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/FakeAssetLoader.kt index fe43e58b7..8d5630566 100644 --- a/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/FakeAssetLoader.kt +++ b/pillarbox-player/src/test/java/ch/srgssr/pillarbox/player/tracker/FakeAssetLoader.kt @@ -18,10 +18,13 @@ class FakeAssetLoader(context: Context) : AssetLoader(DefaultMediaSourceFactory( override suspend fun loadAsset(mediaItem: MediaItem): Asset { val itemBuilder = mediaItem.buildUpon() - val trackerData = if (mediaItem.mediaId == MEDIA_ID_NO_TRACKING_DATA) MediaItemTrackerData.EMPTY - else MediaItemTrackerData.Builder() - .putData(FakeMediaItemTracker::class.java, FakeMediaItemTracker.Data(mediaItem.mediaId)) - .build() + val trackerData = if (mediaItem.mediaId == MEDIA_ID_NO_TRACKING_DATA) { + MediaItemTrackerData.EMPTY + } else { + MediaItemTrackerData.Builder() + .putData(FakeMediaItemTracker::class.java, FakeMediaItemTracker.Data(mediaItem.mediaId)) + .build() + } return Asset( mediaSource = mediaSourceFactory.createMediaSource(itemBuilder.build()), trackersData = trackerData, diff --git a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/exoplayer/ExoPlayerView.kt b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/exoplayer/ExoPlayerView.kt index 689f9729a..c083f786d 100644 --- a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/exoplayer/ExoPlayerView.kt +++ b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/exoplayer/ExoPlayerView.kt @@ -71,7 +71,8 @@ fun ExoPlayerView( view.setShowPreviousButton(showPreviousButton) view.setShutterBackgroundColor(shutterBackgroundColor) view.player = player - }, onRelease = { view -> + }, + onRelease = { view -> view.player = null }, onReset = NoOpUpdate diff --git a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/PlayerSurface.kt b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/PlayerSurface.kt index 3c2b73222..296aebdcb 100644 --- a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/PlayerSurface.kt +++ b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/PlayerSurface.kt @@ -171,11 +171,14 @@ private fun AndroidPlayerSurfaceView(player: Player, modifier: Modifier = Modifi modifier = modifier.clipToBounds(), factory = { context -> PlayerSurfaceView(context) - }, update = { view -> + }, + update = { view -> view.player = player - }, onRelease = { view -> + }, + onRelease = { view -> view.player = null - }, onReset = { view -> + }, + onReset = { view -> // onReset is called before `update` when the composable is reused with a different context. view.player = null } diff --git a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/SphericalSurface.kt b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/SphericalSurface.kt index 90d72e1e7..b81d9afde 100644 --- a/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/SphericalSurface.kt +++ b/pillarbox-ui/src/main/java/ch/srgssr/pillarbox/ui/widget/player/SphericalSurface.kt @@ -22,13 +22,16 @@ fun SphericalSurface(player: Player, modifier: Modifier = Modifier) { modifier = modifier, factory = { context -> SphericalGLSurfaceView(context) - }, update = { view -> + }, + update = { view -> player.setVideoSurfaceView(view) view.onResume() - }, onRelease = { view -> + }, + onRelease = { view -> player.setVideoSurfaceView(null) view.onPause() - }, onReset = { + }, + onReset = { // onReset is called before `update` when the composable is reused with a different context. player.setVideoSurface(null) }