From d465110740f203ba2656e68fe94ac365fa4f47ed Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 16:31:10 +0100 Subject: [PATCH 01/14] Remove Kotlinter --- .githooks/pre-commit | 1 - build.gradle | 1 - code-formatting.gradle | 9 --------- versions.properties | 2 -- 4 files changed, 13 deletions(-) diff --git a/.githooks/pre-commit b/.githooks/pre-commit index e4fdce27070d..12719f1fa0a1 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -2,6 +2,5 @@ #!/bin/bash echo "Running spotless check" ./gradlew spotlessApply - ./gradlew formatKotlin git add `git diff --name-only --cached` exit 0 diff --git a/build.gradle b/build.gradle index a620d932d4d2..f77c98963794 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,6 @@ plugins { id 'org.jetbrains.dokka' id 'com.osacky.fulladle' id 'org.jetbrains.kotlin.android' apply false - id 'org.jmailen.kotlinter' apply false id 'com.google.devtools.ksp' apply false id 'com.diffplug.spotless' apply false } diff --git a/code-formatting.gradle b/code-formatting.gradle index 6e4fdbc1a6d8..225372445714 100644 --- a/code-formatting.gradle +++ b/code-formatting.gradle @@ -1,5 +1,4 @@ apply plugin: 'com.diffplug.spotless' -apply plugin: 'org.jmailen.kotlinter' spotless { java { @@ -16,11 +15,3 @@ spotless { trimTrailingWhitespace() } } - -kotlinter { - disabledRules = ['no-wildcard-imports', 'filename', 'package-name', 'annotation-spacing'] -} - -tasks.register('code_format_checks') { - dependsOn 'spotlessCheck', 'lintKotlin' -} diff --git a/versions.properties b/versions.properties index ee2fb678c824..47005d56da2e 100644 --- a/versions.properties +++ b/versions.properties @@ -17,8 +17,6 @@ plugin.com.osacky.fulladle=0.17.4 plugin.org.jetbrains.kotlin=1.9.24 -plugin.org.jmailen.kotlinter=3.12.0 - plugin.com.google.devtools.ksp=1.9.24-1.0.20 plugin.com.diffplug.spotless=6.1.2 From 3baadf2290afec3a45aba5e2a7bffa92444f6cef Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 16:33:03 +0100 Subject: [PATCH 02/14] Update spotless to latest version --- versions.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.properties b/versions.properties index 47005d56da2e..481a693132a8 100644 --- a/versions.properties +++ b/versions.properties @@ -19,7 +19,7 @@ plugin.org.jetbrains.kotlin=1.9.24 plugin.com.google.devtools.ksp=1.9.24-1.0.20 -plugin.com.diffplug.spotless=6.1.2 +plugin.com.diffplug.spotless=7.1.0 version.android.billingclient=7.1.1 From bb86754a031c9153d17fd6814fba0601bb1ecdbf Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 16:34:55 +0100 Subject: [PATCH 03/14] Add Kotlin formatting to Spotless ratchetFrom means Spotless will apply only to files which have changed since origin/main It also means we need to make some changes to CI due to ensure builds pass due to shallow clones. See https://github.com/diffplug/spotless/tree/main/plugin-gradle#using-ratchetfrom-on-ci-systems for more details. --- .editorconfig | 4 ++++ .github/workflows/ci.yml | 3 ++- .github/workflows/nightly.yml | 3 ++- code-formatting.gradle | 7 +++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index efce1d8a8a87..7a82f7c4eb36 100644 --- a/.editorconfig +++ b/.editorconfig @@ -91,3 +91,7 @@ ij_kotlin_while_on_new_line = false ij_kotlin_wrap_elvis_expressions = 1 ij_kotlin_wrap_expression_body_functions = 1 ij_kotlin_wrap_first_method_in_call_chain = false +ktlint_standard_no-wildcard-imports = disabled +ktlint_standard_filename = disabled +ktlint_standard_package-name = disabled +ktlint_standard_annotation = disabled diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b55b82aa3706..98947505ffcc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: + fetch-depth: 0 # required due to setting Spotless ratchetFrom submodules: recursive - name: Set up JDK version @@ -39,7 +40,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run Code Formatting Checks - run: ./gradlew code_format_checks + run: ./gradlew spotlessCheck unit_tests: name: Unit tests diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index a6b5efc71e5a..ae05a351d4a9 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -18,6 +18,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: + fetch-depth: 0 # required due to setting Spotless ratchetFrom submodules: recursive - name: Set up JDK version @@ -30,7 +31,7 @@ jobs: uses: gradle/actions/setup-gradle@v3 - name: Run Code Formatting Checks - run: ./gradlew code_format_checks + run: ./gradlew spotlessCheck unit_tests: name: Unit tests diff --git a/code-formatting.gradle b/code-formatting.gradle index 225372445714..b0535bc4cea7 100644 --- a/code-formatting.gradle +++ b/code-formatting.gradle @@ -1,6 +1,13 @@ apply plugin: 'com.diffplug.spotless' spotless { + ratchetFrom 'origin/develop' + kotlin { + target("src/**/*.kt") + ktlint("1.7.0") + trimTrailingWhitespace() + indentWithSpaces() + } java { target 'src/*/java/**/*.java' googleJavaFormat('1.22.0').aosp() From 7d8d26e214da4645a9c5a5a13c941fe963c973f7 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 16:49:32 +0100 Subject: [PATCH 04/14] Remove deprecated indentWithSpaces --- code-formatting.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code-formatting.gradle b/code-formatting.gradle index b0535bc4cea7..f941107d6c15 100644 --- a/code-formatting.gradle +++ b/code-formatting.gradle @@ -6,7 +6,7 @@ spotless { target("src/**/*.kt") ktlint("1.7.0") trimTrailingWhitespace() - indentWithSpaces() + leadingTabsToSpaces() } java { target 'src/*/java/**/*.java' @@ -14,11 +14,11 @@ spotless { targetExclude("**/FragmentStateAdapter.java") // temporary removeUnusedImports() trimTrailingWhitespace() - indentWithSpaces() + leadingTabsToSpaces() } format 'xml', { target '**/*.xml' - indentWithSpaces() + leadingTabsToSpaces() trimTrailingWhitespace() } } From 248ceaddb2c9229c2f310d8d9bc3c0c4192fc970 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 16:35:05 +0100 Subject: [PATCH 05/14] Update documentation --- CONTRIBUTING.md | 3 +-- STYLEGUIDE.md | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4ba9fe4ef84c..7c4b98aef9ba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,6 +50,5 @@ If your PR is failing because of that, please make sure that you follow our [sty You can also trigger an automatic code formatting of the code by executing: ``` -./gradleW code_format_checks -./gradleW formatKotlin +./gradleW app:spotlessApply ``` diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 1149d370a5af..a32fb8905ada 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -5,8 +5,8 @@ ### Code formatting -You can check the code formatting correctness by running `./gradleW code_format_checks`. -To adhere to codestyle, please run `./gradleW formatKotlin` and `./gradleW spotlessApply` to autoformat in order to fix any CI issues. +You can check the code formatting correctness by running `./gradleW spotlessCheck`. +To adhere to codestyle, please run `./gradleW spotlessApply` to autoformat and fix any CI issues. If you want to do this automatically upon commit we recommend the existing [pre-commit hook](.githooks/pre-commit): - Pull develop branch From 24ef937c891c656ceb374d95ef222c1ee117bcff Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 16 Jul 2025 18:52:33 +0100 Subject: [PATCH 06/14] Fix ignored files committed Spotless breaks because we have classes and files that have been commited that should technically be ignored by our .gitignore settings. See https://github.com/diffplug/spotless/issues/911#issuecomment-904887074 Therefore we have to either remove these files or move them. In this case the DeviceShield stuff was in a package called "report" which we ignore in .gitignore. Therefore I gave it a new package name We want to keep the icon and I guess we want to keep the copyright folder so I made that work in .gitignore --- .gitignore | 5 +++-- .../vpn-impl/src/main/AndroidManifest.xml | 2 +- .../newtab/AppTrackingProtectionStateView.kt | 6 +++--- .../DeviceShieldAppTrackersInfo.kt | 4 ++-- .../DeviceShieldFragment.kt | 9 +++++---- .../PrivacyReportViewModel.kt | 20 ++++++++++--------- .../DeviceShieldTrackerActivity.kt | 2 +- .../res/layout/activity_app_trackers_info.xml | 2 +- .../vpn/ui/PrivacyReportViewModelTest.kt | 2 +- 9 files changed, 28 insertions(+), 24 deletions(-) rename app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/{report => privacyreport}/DeviceShieldAppTrackersInfo.kt (95%) rename app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/{report => privacyreport}/DeviceShieldFragment.kt (95%) rename app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/{report => privacyreport}/PrivacyReportViewModel.kt (80%) diff --git a/.gitignore b/.gitignore index fe3087c55bb1..8bb8d8797bcb 100644 --- a/.gitignore +++ b/.gitignore @@ -41,9 +41,10 @@ captures/ # Intellij *.iml -.idea/ -.idea/workspace.xml +.idea/* !.idea/icon.svg +!.idea/copyright/ +.idea/workspace.xml # Keystore files *.jks diff --git a/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml b/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml index 4f14a9aea91b..eae0b3d96127 100644 --- a/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml +++ b/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml @@ -28,7 +28,7 @@ android:screenOrientation="portrait" /> - PrivacyReportView.ViewState(vpnState, trackersBlocked, shouldShowCTA()) + ViewState(vpnState, trackersBlocked, shouldShowCTA()) } @VisibleForTesting - fun getReport(): Flow { + fun getReport(): Flow { return repository.getVpnTrackers({ dateOfLastHour() }).map { trackers -> if (trackers.isEmpty()) { - PrivacyReportView.TrackersBlocked("", 0, 0) + TrackersBlocked("", 0, 0) } else { val perApp = trackers.groupBy { it.trackingApp }.toList().sortedByDescending { it.second.sumOf { t -> t.count } } val otherAppsSize = (perApp.size - 1).coerceAtLeast(0) val latestApp = perApp.first().first.appDisplayName - PrivacyReportView.TrackersBlocked(latestApp, otherAppsSize, trackers.sumOf { it.count }) + TrackersBlocked(latestApp, otherAppsSize, trackers.sumOf { it.count }) } } } @@ -74,9 +76,9 @@ class PrivacyReportViewModel @Inject constructor( object PrivacyReportView { data class ViewState( - val vpnState: VpnState, - val trackersBlocked: TrackersBlocked, - val isFeatureEnabled: Boolean, + val vpnState: VpnState, + val trackersBlocked: TrackersBlocked, + val isFeatureEnabled: Boolean, ) data class TrackersBlocked( diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt index 864e05d0e7d8..4b8280950e88 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt @@ -68,7 +68,7 @@ import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnRunningState import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnState import com.duckduckgo.mobile.android.vpn.ui.AppBreakageCategory import com.duckduckgo.mobile.android.vpn.ui.alwayson.AlwaysOnAlertDialogFragment -import com.duckduckgo.mobile.android.vpn.ui.report.DeviceShieldAppTrackersInfo +import com.duckduckgo.mobile.android.vpn.ui.privacyreport.DeviceShieldAppTrackersInfo import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.DeviceShieldTrackerActivityViewModel.ViewEvent import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.DeviceShieldTrackerActivityViewModel.ViewEvent.StartVpn import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.view.DisableVpnDialogOptions diff --git a/app-tracking-protection/vpn-impl/src/main/res/layout/activity_app_trackers_info.xml b/app-tracking-protection/vpn-impl/src/main/res/layout/activity_app_trackers_info.xml index 7dca0b2c6bc6..24909105fe02 100644 --- a/app-tracking-protection/vpn-impl/src/main/res/layout/activity_app_trackers_info.xml +++ b/app-tracking-protection/vpn-impl/src/main/res/layout/activity_app_trackers_info.xml @@ -24,7 +24,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - tools:context=".ui.report.DeviceShieldAppTrackersInfo"> + tools:context=".ui.privacyreport.DeviceShieldAppTrackersInfo"> Date: Wed, 16 Jul 2025 18:53:35 +0100 Subject: [PATCH 07/14] Format the classes edited due to moving package changes As these have "changed" since develop then they need formatting! --- .../newtab/AppTrackingProtectionStateView.kt | 109 ++++++------ .../DeviceShieldAppTrackersInfo.kt | 6 +- .../ui/privacyreport/DeviceShieldFragment.kt | 89 +++++----- .../privacyreport/PrivacyReportViewModel.kt | 26 ++- .../DeviceShieldTrackerActivity.kt | 161 +++++++++--------- .../vpn/ui/PrivacyReportViewModelTest.kt | 90 +++++----- 6 files changed, 247 insertions(+), 234 deletions(-) diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/newtab/AppTrackingProtectionStateView.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/newtab/AppTrackingProtectionStateView.kt index 2f3c5b737539..86cf1fabf10a 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/newtab/AppTrackingProtectionStateView.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/newtab/AppTrackingProtectionStateView.kt @@ -46,10 +46,10 @@ import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.DeviceShieldTracker import com.duckduckgo.newtabpage.api.NewTabPageSection import com.duckduckgo.newtabpage.api.NewTabPageSectionPlugin import dagger.android.support.AndroidSupportInjection -import javax.inject.Inject import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import javax.inject.Inject @InjectWith(ViewScope::class) class AppTrackingProtectionStateView @JvmOverloads constructor( @@ -57,10 +57,7 @@ class AppTrackingProtectionStateView @JvmOverloads constructor( attrs: AttributeSet? = null, defStyle: Int = 0, ) : FrameLayout(context, attrs, defStyle) { - - override fun getTag(): String { - return "AppTP" - } + override fun getTag(): String = "AppTP" @Inject lateinit var deviceShieldPixels: DeviceShieldPixels @@ -83,9 +80,10 @@ class AppTrackingProtectionStateView @JvmOverloads constructor( AndroidSupportInjection.inject(this) super.onAttachedToWindow() - conflatedJob += viewModel.viewStateFlow - .onEach { viewState -> renderViewState(viewState) } - .launchIn(findViewTreeLifecycleOwner()?.lifecycleScope!!) + conflatedJob += + viewModel.viewStateFlow + .onEach { viewState -> renderViewState(viewState) } + .launchIn(findViewTreeLifecycleOwner()?.lifecycleScope!!) deviceShieldPixels.didShowNewTabSummary() @@ -141,49 +139,56 @@ class AppTrackingProtectionStateView @JvmOverloads constructor( val lastTrackingApp = trackerBlocked.latestApp val otherApps = trackerBlocked.otherAppsSize - val textToStyle = if (trackersBlocked == 1) { - when (otherApps) { - 0 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeZeroOtherApps, - trackersBlocked, - lastTrackingApp, - ) - - 1 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeOneOtherApp, - trackersBlocked, - lastTrackingApp, - ) - - else -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeMoreOtherApps, - trackersBlocked, - lastTrackingApp, - otherApps, - ) + val textToStyle = + if (trackersBlocked == 1) { + when (otherApps) { + 0 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeZeroOtherApps, + trackersBlocked, + lastTrackingApp, + ) + + 1 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeOneOtherApp, + trackersBlocked, + lastTrackingApp, + ) + + else -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeMoreOtherApps, + trackersBlocked, + lastTrackingApp, + otherApps, + ) + } + } else { + when (otherApps) { + 0 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesZeroOtherApps, + trackersBlocked, + lastTrackingApp, + ) + + 1 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesOneOtherApp, + trackersBlocked, + lastTrackingApp, + ) + + else -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesMoreOtherApps, + trackersBlocked, + lastTrackingApp, + otherApps, + ) + } } - } else { - when (otherApps) { - 0 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesZeroOtherApps, - trackersBlocked, - lastTrackingApp, - ) - - 1 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesOneOtherApp, - trackersBlocked, - lastTrackingApp, - ) - - else -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesMoreOtherApps, - trackersBlocked, - lastTrackingApp, - otherApps, - ) - } - } binding.deviceShieldCtaHeader.text = HtmlCompat.fromHtml(textToStyle, HtmlCompat.FROM_HTML_MODE_LEGACY) binding.deviceShieldCtaImage.setImageResource(R.drawable.ic_apptp_default) @@ -202,9 +207,7 @@ class AppTrackingProtectionNewTabPageSectionPlugin @Inject constructor( ) : NewTabPageSectionPlugin { override val name = NewTabPageSection.APP_TRACKING_PROTECTION.name - override fun getView(context: Context): View { - return AppTrackingProtectionStateView(context) - } + override fun getView(context: Context): View = AppTrackingProtectionStateView(context) override suspend fun isUserEnabled(): Boolean { if (vpnFeatureRemover.isFeatureRemoved()) { diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldAppTrackersInfo.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldAppTrackersInfo.kt index 728c3d21fe72..c840a4f6bbfc 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldAppTrackersInfo.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldAppTrackersInfo.kt @@ -29,7 +29,6 @@ import javax.inject.Inject @InjectWith(ActivityScope::class) class DeviceShieldAppTrackersInfo : DuckDuckGoActivity() { - @Inject lateinit var deviceShieldPixels: DeviceShieldPixels @@ -55,9 +54,6 @@ class DeviceShieldAppTrackersInfo : DuckDuckGoActivity() { } companion object { - - internal fun intent(context: Context): Intent { - return Intent(context, DeviceShieldAppTrackersInfo::class.java) - } + internal fun intent(context: Context): Intent = Intent(context, DeviceShieldAppTrackersInfo::class.java) } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldFragment.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldFragment.kt index 72a2caf05929..fdcbe3ae605d 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldFragment.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/DeviceShieldFragment.kt @@ -41,13 +41,12 @@ import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason.REV import com.duckduckgo.mobile.android.vpn.ui.privacyreport.PrivacyReportViewModel.PrivacyReportView.TrackersBlocked import com.duckduckgo.mobile.android.vpn.ui.privacyreport.PrivacyReportViewModel.PrivacyReportView.ViewState import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.DeviceShieldTrackerActivity -import javax.inject.Inject import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import javax.inject.Inject @InjectWith(FragmentScope::class) class DeviceShieldFragment : DuckDuckGoFragment() { - @Inject lateinit var viewModelFactory: FragmentViewModelFactory @@ -58,8 +57,7 @@ class DeviceShieldFragment : DuckDuckGoFragment() { private lateinit var deviceShieldCtaHeaderTextView: TextView private lateinit var deviceShieldCtaImageView: ImageView - private inline fun bindViewModel() = - lazy { ViewModelProvider(this, viewModelFactory).get(V::class.java) } + private inline fun bindViewModel() = lazy { ViewModelProvider(this, viewModelFactory).get(V::class.java) } private val viewModel: PrivacyReportViewModel by bindViewModel() @@ -145,45 +143,52 @@ class DeviceShieldFragment : DuckDuckGoFragment() { val lastTrackingApp = trackerBlocked.latestApp val otherApps = trackerBlocked.otherAppsSize - val textToStyle = if (trackersBlocked == 1) { - when (otherApps) { - 0 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeZeroOtherApps, - trackersBlocked, - lastTrackingApp, - ) - 1 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeOneOtherApp, - trackersBlocked, - lastTrackingApp, - ) - else -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeMoreOtherApps, - trackersBlocked, - lastTrackingApp, - otherApps, - ) + val textToStyle = + if (trackersBlocked == 1) { + when (otherApps) { + 0 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeZeroOtherApps, + trackersBlocked, + lastTrackingApp, + ) + 1 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeOneOtherApp, + trackersBlocked, + lastTrackingApp, + ) + else -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOneTimeMoreOtherApps, + trackersBlocked, + lastTrackingApp, + otherApps, + ) + } + } else { + when (otherApps) { + 0 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesZeroOtherApps, + trackersBlocked, + lastTrackingApp, + ) + 1 -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesOneOtherApp, + trackersBlocked, + lastTrackingApp, + ) + else -> + resources.getString( + R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesMoreOtherApps, + trackersBlocked, + lastTrackingApp, + otherApps, + ) + } } - } else { - when (otherApps) { - 0 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesZeroOtherApps, - trackersBlocked, - lastTrackingApp, - ) - 1 -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesOneOtherApp, - trackersBlocked, - lastTrackingApp, - ) - else -> resources.getString( - R.string.atp_DailyLastCompanyBlockedHomeTabOtherTimesMoreOtherApps, - trackersBlocked, - lastTrackingApp, - otherApps, - ) - } - } deviceShieldCtaHeaderTextView.text = HtmlCompat.fromHtml(textToStyle, HtmlCompat.FROM_HTML_MODE_LEGACY) deviceShieldCtaImageView.setImageResource(R.drawable.ic_apptp_default) diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/PrivacyReportViewModel.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/PrivacyReportViewModel.kt index f0e93c3bdd4b..654aa807d3e1 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/PrivacyReportViewModel.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/privacyreport/PrivacyReportViewModel.kt @@ -30,11 +30,11 @@ import com.duckduckgo.mobile.android.vpn.stats.AppTrackerBlockingStatsRepository import com.duckduckgo.mobile.android.vpn.ui.onboarding.VpnStore import com.duckduckgo.mobile.android.vpn.ui.privacyreport.PrivacyReportViewModel.PrivacyReportView.TrackersBlocked import com.duckduckgo.mobile.android.vpn.ui.privacyreport.PrivacyReportViewModel.PrivacyReportView.ViewState -import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext +import javax.inject.Inject @ContributesViewModel(ViewScope::class) class PrivacyReportViewModel @Inject constructor( @@ -44,14 +44,14 @@ class PrivacyReportViewModel @Inject constructor( vpnStateMonitor: VpnStateMonitor, private val dispatchers: DispatcherProvider, ) : ViewModel() { - - val viewStateFlow = vpnStateMonitor.getStateFlow(AppTpVpnFeature.APPTP_VPN).combine(getReport()) { vpnState, trackersBlocked -> - ViewState(vpnState, trackersBlocked, shouldShowCTA()) - } + val viewStateFlow = + vpnStateMonitor.getStateFlow(AppTpVpnFeature.APPTP_VPN).combine(getReport()) { vpnState, trackersBlocked -> + ViewState(vpnState, trackersBlocked, shouldShowCTA()) + } @VisibleForTesting - fun getReport(): Flow { - return repository.getVpnTrackers({ dateOfLastHour() }).map { trackers -> + fun getReport(): Flow = + repository.getVpnTrackers({ dateOfLastHour() }).map { trackers -> if (trackers.isEmpty()) { TrackersBlocked("", 0, 0) } else { @@ -62,23 +62,21 @@ class PrivacyReportViewModel @Inject constructor( TrackersBlocked(latestApp, otherAppsSize, trackers.sumOf { it.count }) } } - } - private suspend fun shouldShowCTA(): Boolean { - return withContext(dispatchers.io()) { + private suspend fun shouldShowCTA(): Boolean = + withContext(dispatchers.io()) { if (vpnFeatureRemover.isFeatureRemoved()) { false } else { vpnStore.didShowOnboarding() } } - } object PrivacyReportView { data class ViewState( - val vpnState: VpnState, - val trackersBlocked: TrackersBlocked, - val isFeatureEnabled: Boolean, + val vpnState: VpnState, + val trackersBlocked: TrackersBlocked, + val isFeatureEnabled: Boolean, ) data class TrackersBlocked( diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt index 4b8280950e88..df1987345559 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/tracker_activity/DeviceShieldTrackerActivity.kt @@ -76,9 +76,6 @@ import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.view.message.AppTPS import com.duckduckgo.mobile.android.vpn.ui.tracker_activity.view.message.AppTPStateMessagePlugin.DefaultAppTPMessageAction import com.duckduckgo.navigation.api.GlobalActivityStarter import com.google.android.material.snackbar.Snackbar -import java.util.concurrent.TimeUnit -import javax.inject.Inject -import javax.inject.Provider import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.combine @@ -88,13 +85,15 @@ import kotlinx.coroutines.launch import logcat.logcat import nl.dionsegijn.konfetti.models.Shape import nl.dionsegijn.konfetti.models.Size +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import javax.inject.Provider @InjectWith(ActivityScope::class) @ContributeToActivityStarter(AppTrackerActivityWithEmptyParams::class, screenName = "apptp.main") class DeviceShieldTrackerActivity : DuckDuckGoActivity(), DeviceShieldActivityFeedFragment.DeviceShieldActivityFeedListener { - @Inject lateinit var deviceShieldPixels: DeviceShieldPixels @@ -125,20 +124,22 @@ class DeviceShieldTrackerActivity : // we might get an update before options menu has been populated; temporarily cache value to use when menu populated private var vpnCachedState: VpnState? = null - private val feedConfig = DeviceShieldActivityFeedFragment.ActivityFeedConfig( - maxRows = MIN_ROWS_FOR_ALL_ACTIVITY, - timeWindow = 7, - timeWindowUnits = TimeUnit.DAYS, - showTimeWindowHeadings = false, - ) + private val feedConfig = + DeviceShieldActivityFeedFragment.ActivityFeedConfig( + maxRows = MIN_ROWS_FOR_ALL_ACTIVITY, + timeWindow = 7, + timeWindowUnits = TimeUnit.DAYS, + showTimeWindowHeadings = false, + ) private val viewModel: DeviceShieldTrackerActivityViewModel by bindViewModel() private lateinit var reportBreakage: ActivityResultLauncher - private val enableAppTPSwitchListener = CompoundButton.OnCheckedChangeListener { _, isChecked -> - viewModel.onAppTPToggleSwitched(isChecked) - } + private val enableAppTPSwitchListener = + CompoundButton.OnCheckedChangeListener { _, isChecked -> + viewModel.onAppTPToggleSwitched(isChecked) + } private val onInfoMessageClick = fun(action: DefaultAppTPMessageAction) { when (action) { @@ -153,11 +154,12 @@ class DeviceShieldTrackerActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - reportBreakage = registerForActivityResult(reportBreakageContract.get()) { - if (!it.isEmpty()) { - Snackbar.make(binding.root, R.string.atp_ReportBreakageSent, Snackbar.LENGTH_LONG).show() + reportBreakage = + registerForActivityResult(reportBreakageContract.get()) { + if (!it.isEmpty()) { + Snackbar.make(binding.root, R.string.atp_ReportBreakageSent, Snackbar.LENGTH_LONG).show() + } } - } setContentView(binding.root) setupToolbar(binding.includeToolbar.trackersToolbar) @@ -231,31 +233,31 @@ class DeviceShieldTrackerActivity : } private fun showDeviceShieldActivity() { - supportFragmentManager.beginTransaction() + supportFragmentManager + .beginTransaction() .replace( R.id.activity_list, DeviceShieldActivityFeedFragment.newInstance(feedConfig), - ) - .commitNow() + ).commitNow() } @OptIn(FlowPreview::class) private fun observeViewModel() { lifecycleScope.launch { - viewModel.getBlockedTrackersCount() + viewModel + .getBlockedTrackersCount() .combine(viewModel.getTrackingAppsCount()) { trackers, apps -> DeviceShieldTrackerActivityViewModel.TrackerCountInfo(trackers, apps) - } - .combine(viewModel.getRunningState()) { trackerCountInfo, runningState -> + }.combine(viewModel.getRunningState()) { trackerCountInfo, runningState -> DeviceShieldTrackerActivityViewModel.TrackerActivityViewState(trackerCountInfo, runningState) - } - .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) + }.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) .collect { renderViewState(it) } } lifecycleScope.launch { // This is a one-shot check as soon as the screen is shown - viewModel.getRunningState() + viewModel + .getRunningState() .map { it.alwaysOnState } .debounce(500) // give a bit of time so that pop doesn't just suddenly pops up .take(1) @@ -266,7 +268,8 @@ class DeviceShieldTrackerActivity : } } - viewModel.commands() + viewModel + .commands() .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED) .onEach { processCommand(it) } .launchIn(lifecycleScope) @@ -348,8 +351,7 @@ class DeviceShieldTrackerActivity : } } }, - ) - .show() + ).show() } private fun launchRemoveFeatureConfirmationDialog() { @@ -370,8 +372,7 @@ class DeviceShieldTrackerActivity : deviceShieldPixels.didChooseToCancelRemoveTrakcingProtectionDialog() } }, - ) - .show() + ).show() } private fun showVpnConflictDialog() { @@ -392,8 +393,7 @@ class DeviceShieldTrackerActivity : onVpnConflictDialogDismiss() } }, - ) - .show() + ).show() } private fun showAlwaysOnConflictDialog() { @@ -413,42 +413,43 @@ class DeviceShieldTrackerActivity : onVpnConflictDialogDismiss() } }, - ) - .show() + ).show() } private fun launchAlwaysOnPromotionDialog() { val dialog = supportFragmentManager.findFragmentByTag(TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) as? AlwaysOnAlertDialogFragment dialog?.dismiss() - AlwaysOnAlertDialogFragment.newAlwaysOnDialog( - object : AlwaysOnAlertDialogFragment.Listener { - override fun onGoToSettingsClicked() { - viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnOpenSettings) - } + AlwaysOnAlertDialogFragment + .newAlwaysOnDialog( + object : AlwaysOnAlertDialogFragment.Listener { + override fun onGoToSettingsClicked() { + viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnOpenSettings) + } - override fun onCanceled() { - viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnCancelled) - } - }, - ).show(supportFragmentManager, TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) + override fun onCanceled() { + viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnCancelled) + } + }, + ).show(supportFragmentManager, TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) } private fun launchAlwaysOnLockdownEnabledDialog() { val dialog = supportFragmentManager.findFragmentByTag(TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) as? AlwaysOnAlertDialogFragment dialog?.dismiss() - AlwaysOnAlertDialogFragment.newAlwaysOnLockdownDialog( - object : AlwaysOnAlertDialogFragment.Listener { - override fun onGoToSettingsClicked() { - viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnOpenSettings) - } + AlwaysOnAlertDialogFragment + .newAlwaysOnLockdownDialog( + object : AlwaysOnAlertDialogFragment.Listener { + override fun onGoToSettingsClicked() { + viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnOpenSettings) + } - override fun onCanceled() { - viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnCancelled) - } - }, - ).show(supportFragmentManager, TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) + override fun onCanceled() { + viewModel.onViewEvent(ViewEvent.PromoteAlwaysOnCancelled) + } + }, + ).show(supportFragmentManager, TAG_APPTP_PROMOTE_ALWAYS_ON_DIALOG) } fun onOpenAppProtection() { @@ -562,18 +563,20 @@ class DeviceShieldTrackerActivity : private suspend fun updateRunningState(runningState: VpnState) { if (!binding.deviceShieldTrackerNotifyMe.isVisible) { var newActivePlugin: ActivePlugin? = null - appTPStateMessagePluginPoint.getPlugins().firstNotNullOfOrNull { - it.getView(this, runningState, onInfoMessageClick)?.apply { - newActivePlugin = it - } - }?.let { - if (currenActivePlugin == null || newActivePlugin != currenActivePlugin) { - currenActivePlugin = newActivePlugin - binding.deviceShieldTrackerMessageContainer.show() - binding.deviceShieldTrackerMessageContainer.removeAllViews() - binding.deviceShieldTrackerMessageContainer.addView(it) - } - } ?: { + appTPStateMessagePluginPoint + .getPlugins() + .firstNotNullOfOrNull { + it.getView(this, runningState, onInfoMessageClick)?.apply { + newActivePlugin = it + } + }?.let { + if (currenActivePlugin == null || newActivePlugin != currenActivePlugin) { + currenActivePlugin = newActivePlugin + binding.deviceShieldTrackerMessageContainer.show() + binding.deviceShieldTrackerMessageContainer.removeAllViews() + binding.deviceShieldTrackerMessageContainer.addView(it) + } + } ?: { currenActivePlugin = null binding.deviceShieldTrackerMessageContainer.gone() } @@ -626,7 +629,10 @@ class DeviceShieldTrackerActivity : private sealed class VpnPermissionStatus { object Granted : VpnPermissionStatus() - data class Denied(val intent: Intent) : VpnPermissionStatus() + + data class Denied( + val intent: Intent, + ) : VpnPermissionStatus() } private fun showAppTpEnabledCta() { @@ -634,11 +640,12 @@ class DeviceShieldTrackerActivity : return } - val dialog = TypewriterDaxDialog.newInstance( - daxText = getString(R.string.atp_ActivityAppTpEnabledCtaText), - primaryButtonText = getString(R.string.atp_ActivityAppTpEnabledCtaButtonLabel), - hideButtonText = "", - ) + val dialog = + TypewriterDaxDialog.newInstance( + daxText = getString(R.string.atp_ActivityAppTpEnabledCtaText), + primaryButtonText = getString(R.string.atp_ActivityAppTpEnabledCtaButtonLabel), + hideButtonText = "", + ) dialog.setDaxDialogListener( object : DaxDialogListener { @@ -674,7 +681,8 @@ class DeviceShieldTrackerActivity : val displayWidth = resources.displayMetrics.widthPixels - binding.appTpEnabledKonfetti.build() + binding.appTpEnabledKonfetti + .build() .addColors(magenta, blue, purple, green, yellow) .setDirection(0.0, 359.0) .setSpeed(4f, 9f) @@ -699,10 +707,9 @@ class DeviceShieldTrackerActivity : internal fun intent( context: Context, onLaunchCallback: ResultReceiver? = null, - ): Intent { - return Intent(context, DeviceShieldTrackerActivity::class.java).apply { + ): Intent = + Intent(context, DeviceShieldTrackerActivity::class.java).apply { putExtra(RESULT_RECEIVER_EXTRA, onLaunchCallback) } - } } } diff --git a/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/ui/PrivacyReportViewModelTest.kt b/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/ui/PrivacyReportViewModelTest.kt index ad3ec798691e..461fb3d9910d 100644 --- a/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/ui/PrivacyReportViewModelTest.kt +++ b/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/ui/PrivacyReportViewModelTest.kt @@ -33,8 +33,6 @@ import com.duckduckgo.mobile.android.vpn.store.VpnDatabase import com.duckduckgo.mobile.android.vpn.trackers.AppTrackerEntity import com.duckduckgo.mobile.android.vpn.ui.onboarding.VpnStore import com.duckduckgo.mobile.android.vpn.ui.privacyreport.PrivacyReportViewModel -import java.time.LocalDateTime -import kotlin.time.ExperimentalTime import kotlinx.coroutines.runBlocking import org.junit.After import org.junit.Assert.assertEquals @@ -43,11 +41,12 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.mock +import java.time.LocalDateTime +import kotlin.time.ExperimentalTime @ExperimentalTime @RunWith(AndroidJUnit4::class) class PrivacyReportViewModelTest { - @get:Rule @Suppress("unused") var instantTaskExecutorRule = InstantTaskExecutorRule() @@ -74,9 +73,11 @@ class PrivacyReportViewModelTest { } private fun prepareDb() { - db = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().targetContext, VpnDatabase::class.java) - .allowMainThreadQueries() - .build() + db = + Room + .inMemoryDatabaseBuilder(InstrumentationRegistry.getInstrumentation().targetContext, VpnDatabase::class.java) + .allowMainThreadQueries() + .build() } @After @@ -85,39 +86,42 @@ class PrivacyReportViewModelTest { } @Test - fun whenTrackersBlockedThenReportHasTrackers() = runBlocking { - trackerFound("dax.com") - trackerFound("dax.com") - trackerFound("dax.com") - - testee.getReport().test { - val result = awaitItem() - assertEquals(3, result.trackers) - cancelAndConsumeRemainingEvents() + fun whenTrackersBlockedThenReportHasTrackers() = + runBlocking { + trackerFound("dax.com") + trackerFound("dax.com") + trackerFound("dax.com") + + testee.getReport().test { + val result = awaitItem() + assertEquals(3, result.trackers) + cancelAndConsumeRemainingEvents() + } } - } @Test - fun whenTrackersBlockedOutsideTimeWindowThenReturnEmpty() = runBlocking { - trackerFoundYesterday("dax.com") - trackerFoundYesterday("dax.com") - trackerFoundYesterday("dax.com") - - testee.getReport().test { - val result = awaitItem() - assertEquals(0, result.trackers) - cancelAndConsumeRemainingEvents() + fun whenTrackersBlockedOutsideTimeWindowThenReturnEmpty() = + runBlocking { + trackerFoundYesterday("dax.com") + trackerFoundYesterday("dax.com") + trackerFoundYesterday("dax.com") + + testee.getReport().test { + val result = awaitItem() + assertEquals(0, result.trackers) + cancelAndConsumeRemainingEvents() + } } - } @Test - fun whenNoTrackersBlockedThenReportIsEmpty() = runBlocking { - testee.getReport().test { - val result = awaitItem() - assertEquals(0, result.trackers) - cancelAndConsumeRemainingEvents() + fun whenNoTrackersBlockedThenReportIsEmpty() = + runBlocking { + testee.getReport().test { + val result = awaitItem() + assertEquals(0, result.trackers) + cancelAndConsumeRemainingEvents() + } } - } private fun trackerFoundYesterday(trackerDomain: String = "example.com") { trackerFound(trackerDomain, timestamp = yesterday()) @@ -129,14 +133,15 @@ class PrivacyReportViewModelTest { timestamp: String = DatabaseDateFormatter.bucketByHour(), ) { val defaultTrackingApp = TrackingApp("app.foo.com", "Foo App") - val tracker = VpnTracker( - trackerCompanyId = trackerCompanyId, - domain = domain, - timestamp = timestamp, - company = "", - companyDisplayName = "", - trackingApp = defaultTrackingApp, - ) + val tracker = + VpnTracker( + trackerCompanyId = trackerCompanyId, + domain = domain, + timestamp = timestamp, + company = "", + companyDisplayName = "", + trackingApp = defaultTrackingApp, + ) val trackers = listOf(tracker) repository.insert(trackers) db.vpnAppTrackerBlockingDao().insertTrackerEntities(trackers.map { it.asEntity() }) @@ -148,12 +153,11 @@ class PrivacyReportViewModelTest { return DatabaseDateFormatter.bucketByHour(yesterday) } - private fun VpnTracker.asEntity(): AppTrackerEntity { - return AppTrackerEntity( + private fun VpnTracker.asEntity(): AppTrackerEntity = + AppTrackerEntity( trackerCompanyId = this.trackerCompanyId, entityName = "name", score = 0, signals = emptyList(), ) - } } From 2b2e10ebd501f36297820be864b7e349c77655ef Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Mon, 21 Jul 2025 08:36:51 +0200 Subject: [PATCH 08/14] Update Spotless plugin version to 7.2.0 --- versions.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.properties b/versions.properties index 481a693132a8..db3d7a14d496 100644 --- a/versions.properties +++ b/versions.properties @@ -19,7 +19,7 @@ plugin.org.jetbrains.kotlin=1.9.24 plugin.com.google.devtools.ksp=1.9.24-1.0.20 -plugin.com.diffplug.spotless=7.1.0 +plugin.com.diffplug.spotless=7.2.0 version.android.billingclient=7.1.1 From 6167e0a7a5617c4d1c539863728fa1b93e81b8ff Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Tue, 22 Jul 2025 09:55:18 +0200 Subject: [PATCH 09/14] WIP --- code-formatting.gradle | 4 ++-- versions.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code-formatting.gradle b/code-formatting.gradle index f941107d6c15..8b761cd5d17d 100644 --- a/code-formatting.gradle +++ b/code-formatting.gradle @@ -3,8 +3,8 @@ apply plugin: 'com.diffplug.spotless' spotless { ratchetFrom 'origin/develop' kotlin { - target("src/**/*.kt") - ktlint("1.7.0") + target 'src/*/kotlin/**/*.kt', 'src/*/java/**/*.kt' + ktlint("1.7.1") trimTrailingWhitespace() leadingTabsToSpaces() } diff --git a/versions.properties b/versions.properties index db3d7a14d496..a49a7ca40fca 100644 --- a/versions.properties +++ b/versions.properties @@ -19,7 +19,7 @@ plugin.org.jetbrains.kotlin=1.9.24 plugin.com.google.devtools.ksp=1.9.24-1.0.20 -plugin.com.diffplug.spotless=7.2.0 +plugin.com.diffplug.spotless=7.2.1 version.android.billingclient=7.1.1 From 12b5434cf72e772d514cbe62b67a30405b55049b Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 23 Jul 2025 19:10:37 +0200 Subject: [PATCH 10/14] Refactor build.gradle to use plugins block for Kotlin and Java library I could remove this long ago when changing to plugin blocks, now it works --- lint-rules/build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lint-rules/build.gradle b/lint-rules/build.gradle index e9d01477ba18..eb5caeaa0ea0 100644 --- a/lint-rules/build.gradle +++ b/lint-rules/build.gradle @@ -14,8 +14,10 @@ * limitations under the License. */ -apply plugin: 'java-library' -apply plugin: 'kotlin' +plugins { + id 'java-library' + id 'kotlin' +} dependencies { compileOnly Kotlin.stdlib.jdk7 From 1d4bab8036f519309c876a3f9d1abf3eb1aee900 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 23 Jul 2025 19:11:55 +0200 Subject: [PATCH 11/14] Remove unused Kotlin stdlib dependency from build.gradle This gets added by default, not need for us to specify it and avoids any issues. --- lint-rules/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/lint-rules/build.gradle b/lint-rules/build.gradle index eb5caeaa0ea0..a36c3fd610e5 100644 --- a/lint-rules/build.gradle +++ b/lint-rules/build.gradle @@ -20,7 +20,6 @@ plugins { } dependencies { - compileOnly Kotlin.stdlib.jdk7 compileOnly "com.android.tools.lint:lint-api:$lint_version" compileOnly "com.android.tools.lint:lint-checks:$lint_version" From 6d6b452cf05fbb0f984428aee59f8b3ddbf53d9d Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 23 Jul 2025 19:13:21 +0200 Subject: [PATCH 12/14] Update Kotlin to 2.2.0 & KSP to 2.2.0-2.0.2 Removed the extra version.kotlin declared as I believe it's redundant --- versions.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/versions.properties b/versions.properties index a49a7ca40fca..61649f34c8f9 100644 --- a/versions.properties +++ b/versions.properties @@ -15,9 +15,9 @@ plugin.org.jetbrains.dokka=1.8.20 plugin.com.osacky.fulladle=0.17.4 -plugin.org.jetbrains.kotlin=1.9.24 +plugin.org.jetbrains.kotlin=2.2.0 -plugin.com.google.devtools.ksp=1.9.24-1.0.20 +plugin.com.google.devtools.ksp=2.2.0-2.0.2 plugin.com.diffplug.spotless=7.2.1 @@ -111,7 +111,7 @@ version.io.jsonwebtoken..jjwt-orgjson=0.12.6 version.jakewharton.rxrelay2=2.0.0 -version.kotlin=1.9.24 +version.kotlin=2.2.0 version.kotlinx.coroutines=1.8.1 From e66b36b978f423ca1760073d7695085b5f5d3338 Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 23 Jul 2025 19:04:57 +0200 Subject: [PATCH 13/14] Fix broken Room code generation We use Kotlin CodeGen for Room in the app module, but not in other modules. This along with KSP2 breaks the update to Kotlin 2.2.0 We can turn KSP2 off for now and ensure that any module that adds the Room compiler generates Kotlin code. This will be the default in Kotlin 2.7.0+ but we cannot use it right now as we get occasional build issues. See the Asana task for more info. --- build.gradle | 16 ++++++++++++++++ gradle.properties | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f77c98963794..65b3b930d033 100644 --- a/build.gradle +++ b/build.gradle @@ -160,6 +160,22 @@ subprojects { } } } + + plugins.withId('com.google.devtools.ksp') { + afterEvaluate { + configurations.configureEach { config -> + if (config.name == 'ksp') { + config.dependencies.matching { + it.group == 'androidx.room' && it.name == 'room-compiler' + }.configureEach { + ksp { + arg("room.generateKotlin", "true") + } + } + } + } + } + } } task clean(type: Delete) { diff --git a/gradle.properties b/gradle.properties index 530c09b94b8b..c4e3bdf645c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,4 +22,4 @@ org.gradle.parallel=true org.gradle.configureondemand=true android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=false - +ksp.useKSP2=false From 4476655fe800d0d30a8c39bfd786a10cf8dc667d Mon Sep 17 00:00:00 2001 From: Mike Scamell Date: Wed, 23 Jul 2025 19:35:46 +0200 Subject: [PATCH 14/14] Update Anvil to 2.6.1, Dagger to 2.56.2 This also required some code changes to remove some deprecated classes. --- .../ContributeToActivityStarterCodeGenerator.kt | 6 +++--- .../ContributesPluginPointCodeGenerator.kt | 10 +++++----- .../ContributesRemoteFeatureCodeGenerator.kt | 10 +++++----- .../compiler/ContributesServiceApiCodeGenerator.kt | 6 +++--- .../ContributesSubComponentCodeGenerator.kt | 14 +++++++------- .../compiler/ContributesViewModelCodeGenerator.kt | 6 +++--- .../compiler/ContributesWorkerCodeGenerator.kt | 7 ++++--- versions.properties | 4 ++-- 8 files changed, 32 insertions(+), 31 deletions(-) diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributeToActivityStarterCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributeToActivityStarterCodeGenerator.kt index e0e83437e15a..b169a18cacdb 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributeToActivityStarterCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributeToActivityStarterCodeGenerator.kt @@ -40,7 +40,7 @@ class ContributeToActivityStarterCodeGenerator : CodeGenerator { override fun isApplicable(context: AnvilContext): Boolean = true - override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { + override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(ContributeToActivityStarter::class.fqName) } @@ -52,7 +52,7 @@ class ContributeToActivityStarterCodeGenerator : CodeGenerator { .toList() } - private fun generateParameterToActivityMapper(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateParameterToActivityMapper(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val moduleClassName = "${vmClass.shortName}_ActivityMapper" @@ -73,7 +73,7 @@ class ContributeToActivityStarterCodeGenerator : CodeGenerator { } } - return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content, vmClass.containingFileAsJavaFile) } private fun createMapperClass( diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesPluginPointCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesPluginPointCodeGenerator.kt index fc6621ad4d69..1e637bf36afa 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesPluginPointCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesPluginPointCodeGenerator.kt @@ -45,7 +45,7 @@ class ContributesPluginPointCodeGenerator : CodeGenerator { override fun isApplicable(context: AnvilContext): Boolean = true - override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { + override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(ContributesPluginPoint::class.fqName) } @@ -58,7 +58,7 @@ class ContributesPluginPointCodeGenerator : CodeGenerator { .toList() } - private fun generatePluginPoint(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generatePluginPoint(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val pluginPointClassName = "${vmClass.shortName}_PluginPoint" val scope = vmClass.annotations.first { it.fqName == ContributesPluginPoint::class.fqName }.scopeOrNull(0)!! @@ -132,10 +132,10 @@ class ContributesPluginPointCodeGenerator : CodeGenerator { ) } - return createGeneratedFile(codeGenDir, generatedPackage, pluginPointClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, pluginPointClassName, content, vmClass.containingFileAsJavaFile) } - private fun generateBindingModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateBindingModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val moduleClassName = "${vmClass.shortName}_PluginPoint_Module" val scope = vmClass.annotations.first { it.fqName == ContributesPluginPoint::class.fqName }.scopeOrNull(0)!! @@ -180,7 +180,7 @@ class ContributesPluginPointCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content, vmClass.containingFileAsJavaFile) } companion object { diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt index 4dbd919c7a5c..69a473af9201 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt @@ -51,7 +51,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection, - ): Collection { + ): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(ContributesRemoteFeature::class.fqName) } @@ -72,7 +72,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { codeGenDir: File, module: ModuleDescriptor, customStorePresence: CustomStorePresence, - ): GeneratedFile { + ): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val generatedClassName = "${vmClass.shortName}_ProxyModule" val annotation = vmClass.annotations.first { it.fqName == ContributesRemoteFeature::class.fqName } @@ -187,7 +187,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { ) } - return createGeneratedFile(codeGenDir, generatedPackage, generatedClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, generatedClassName, content, vmClass.containingFileAsJavaFile) } private fun generateRemoteFeature( @@ -195,7 +195,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { codeGenDir: File, module: ModuleDescriptor, customStorePresence: CustomStorePresence, - ): GeneratedFile { + ): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val generatedClassName = "${vmClass.shortName}_RemoteFeature" val annotation = vmClass.annotations.first { it.fqName == ContributesRemoteFeature::class.fqName } @@ -319,7 +319,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator { ) } - return createGeneratedFile(codeGenDir, generatedPackage, generatedClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, generatedClassName, content, vmClass.containingFileAsJavaFile) } private fun generateOptionalBindings( diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesServiceApiCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesServiceApiCodeGenerator.kt index 87b70f2229fe..cb217447c690 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesServiceApiCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesServiceApiCodeGenerator.kt @@ -46,7 +46,7 @@ class ContributesServiceApiCodeGenerator : CodeGenerator { override fun isApplicable(context: AnvilContext): Boolean = true - override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { + override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { reference -> reference.isAnnotatedWith(serviceApiAnnotations.map { it.fqName }) } @@ -58,7 +58,7 @@ class ContributesServiceApiCodeGenerator : CodeGenerator { .toList() } - private fun generateServiceApiModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateServiceApiModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val moduleClassName = "${vmClass.shortName}_Module" @@ -125,7 +125,7 @@ class ContributesServiceApiCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content, vmClass.containingFileAsJavaFile) } private fun ClassReference.Psi.serviceApiClassName( diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesSubComponentCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesSubComponentCodeGenerator.kt index a24bc91eafd8..9c1bbba4acd8 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesSubComponentCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesSubComponentCodeGenerator.kt @@ -50,7 +50,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { override fun isApplicable(context: AnvilContext): Boolean = true - override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { + override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(InjectWith::class.fqName) } @@ -69,7 +69,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { .toList() } - private fun generateActivityInjector(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateActivityInjector(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val activityInjectorInterfaceName = "${vmClass.shortName}_Injector" val scope = vmClass.annotations.first { it.fqName == InjectWith::class.fqName }.scopeOrNull(0)!! @@ -105,9 +105,9 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, activityInjectorInterfaceName, content) + return createGeneratedFile(codeGenDir, generatedPackage, activityInjectorInterfaceName, content, vmClass.containingFileAsJavaFile) } - private fun generateSubcomponentFactory(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateSubcomponentFactory(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val subcomponentFactoryClassName = vmClass.subComponentName() val scope = vmClass.annotations.first { it.fqName == InjectWith::class.fqName }.scopeOrNull(0)!! @@ -159,7 +159,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, subcomponentFactoryClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, subcomponentFactoryClassName, content, vmClass.containingFileAsJavaFile) } private fun generateParentComponentInterface(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): TypeSpec { @@ -184,7 +184,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { .build() } - private fun generateSubcomponentFactoryBindingModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateSubcomponentFactoryBindingModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val moduleClassName = "${vmClass.subComponentName()}_Module" val scope = vmClass.annotations.first { it.fqName == InjectWith::class.fqName }.scopeOrNull(0)!! @@ -219,7 +219,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content, vmClass.containingFileAsJavaFile) } private fun FqName.subComponentAnnotation(module: ModuleDescriptor, delayGeneration: Boolean): AnnotationSpec { diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesViewModelCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesViewModelCodeGenerator.kt index 139c07eb6962..0635352c611f 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesViewModelCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesViewModelCodeGenerator.kt @@ -42,7 +42,7 @@ class ContributesViewModelCodeGenerator : CodeGenerator { override fun isApplicable(context: AnvilContext): Boolean = true - override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { + override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection): Collection { return projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(ContributesViewModel::class.fqName) } @@ -52,7 +52,7 @@ class ContributesViewModelCodeGenerator : CodeGenerator { .toList() } - private fun generateFactoryPlugin(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile { + private fun generateFactoryPlugin(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val factoryClassName = "${vmClass.shortName}_ViewModelFactory" val scope = vmClass.annotations.first { it.fqName == ContributesViewModel::class.fqName }.scopeOrNull(0) @@ -122,7 +122,7 @@ class ContributesViewModelCodeGenerator : CodeGenerator { ).build() } - return createGeneratedFile(codeGenDir, generatedPackage, factoryClassName, content) + return createGeneratedFile(codeGenDir, generatedPackage, factoryClassName, content, vmClass.containingFileAsJavaFile) } companion object { diff --git a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesWorkerCodeGenerator.kt b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesWorkerCodeGenerator.kt index 2e256ffa22f5..a6cbfcc99fb6 100644 --- a/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesWorkerCodeGenerator.kt +++ b/anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesWorkerCodeGenerator.kt @@ -23,6 +23,7 @@ import com.squareup.anvil.annotations.ExperimentalAnvilApi import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFile +import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.internal.asClassName import com.squareup.anvil.compiler.internal.buildFile @@ -59,7 +60,7 @@ class ContributesWorkerCodeGenerator : CodeGenerator { codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection, - ): Collection = projectFiles.classAndInnerClassReferences(module) + ): Collection = projectFiles.classAndInnerClassReferences(module) .toList() .filter { it.isAnnotatedWith(ContributesWorker::class.fqName) } .flatMap { @@ -71,7 +72,7 @@ class ContributesWorkerCodeGenerator : CodeGenerator { vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor, - ): GeneratedFile { + ): GeneratedFileWithSources { val generatedPackage = vmClass.packageFqName.toString() val workerPluginName = "${vmClass.shortName}_WorkerInjectorPlugin" val scope = vmClass.annotations.first { it.fqName == ContributesWorker::class.fqName }.scopeOrNull(0) @@ -125,7 +126,7 @@ class ContributesWorkerCodeGenerator : CodeGenerator { ) } - return createGeneratedFile(codeGenDir, generatedPackage, workerPluginName, content) + return createGeneratedFile(codeGenDir, generatedPackage, workerPluginName, content, vmClass.containingFileAsJavaFile) } private fun generateCode( diff --git a/versions.properties b/versions.properties index 61649f34c8f9..057d9101522f 100644 --- a/versions.properties +++ b/versions.properties @@ -9,7 +9,7 @@ plugin.android=8.7.3 -plugin.com.squareup.anvil=2.5.0 +plugin.com.squareup.anvil=2.6.1 plugin.org.jetbrains.dokka=1.8.20 @@ -99,7 +99,7 @@ version.com.nhaarman.mockitokotlin2..mockito-kotlin=2.2.0 version.google.android.material=1.12.0 -version.google.dagger=2.51.1 +version.google.dagger=2.56.2 version.io.github.pcmind..leveldb=1.2