Skip to content

refactor(adapter): extract logic from search adapter#551

Merged
waffiqaziz merged 5 commits intomainfrom
dev-refactor
Apr 5, 2026
Merged

refactor(adapter): extract logic from search adapter#551
waffiqaziz merged 5 commits intomainfrom
dev-refactor

Conversation

@waffiqaziz
Copy link
Copy Markdown
Owner

Changes Made

  • Move business logic out of adapter
  • Improve testability and separation of concerns

- Move business logic out of adapter
- Improve testability and separation of concerns
@waffiqaziz waffiqaziz self-assigned this Apr 4, 2026
@waffiqaziz waffiqaziz added the refactor Change implementation or structure without changing behavior. label Apr 4, 2026
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Refactor: Extract domain interfaces and centralize utility logic

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Extract domain interfaces for reusable media properties across models
• Move image and date handling logic to utility extensions
• Refactor search adapter to use centralized utility functions
• Add comprehensive tests for new utility functions and helpers
Diagram
flowchart LR
  A["Domain Interfaces<br/>Dateable, Imageble, Titleable<br/>ProfileImageable"] -->|"implemented by"| B["MediaItem<br/>MultiSearchItem"]
  B -->|"used by"| C["DetailDataUtils<br/>Extensions"]
  B -->|"used by"| D["MediaHelper<br/>Extensions"]
  B -->|"used by"| E["SearchHelper<br/>Extensions"]
  C -->|"simplifies"| F["DetailUIManager"]
  D -->|"simplifies"| F
  E -->|"simplifies"| G["SearchAdapter"]
Loading

Grey Divider

File Changes

1. core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Dateable.kt ✨ Enhancement +6/-0

New interface for date properties

core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Dateable.kt


2. core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Imageble.kt ✨ Enhancement +6/-0

New interface for image path properties

core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Imageble.kt


3. core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Titleable.kt ✨ Enhancement +8/-0

New interface for title properties

core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/Titleable.kt


View more (14)
4. core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/ProfileImageable.kt ✨ Enhancement +5/-0

New interface for profile image property

core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/ProfileImageable.kt


5. core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/MediaItem.kt ✨ Enhancement +12/-9

Implement new domain interfaces

core/domain/src/main/kotlin/com/waffiq/bazz_movies/core/domain/MediaItem.kt


6. core/utils/build.gradle.kts Dependencies +1/-0

Add core:common dependency

core/utils/build.gradle.kts


7. core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt ✨ Enhancement +73/-16

Add image and date utility extensions

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt


8. core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelper.kt ✨ Enhancement +12/-0

Add genre retrieval with fallback utility

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelper.kt


9. core/utils/src/test/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtilsTest.kt 🧪 Tests +115/-16

Add tests for image and date utilities

core/utils/src/test/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtilsTest.kt


10. core/utils/src/test/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelperRoboTest.kt 🧪 Tests +27/-0

New test class for genre helper

core/utils/src/test/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelperRoboTest.kt


11. feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt ✨ Enhancement +10/-35

Refactor to use centralized utility functions

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt


12. feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt ✨ Enhancement +38/-0

Add image and overview utility extensions

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt


13. feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/domain/model/MultiSearchItem.kt ✨ Enhancement +17/-10

Implement domain interfaces for search model

feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/domain/model/MultiSearchItem.kt


14. feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/ui/SearchAdapter.kt ✨ Enhancement +19/-45

Refactor to use centralized utility functions

feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/ui/SearchAdapter.kt


15. feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/utils/SearchHelper.kt ✨ Enhancement +31/-1

Add profile image utility extensions

feature/search/src/main/kotlin/com/waffiq/bazz_movies/feature/search/utils/SearchHelper.kt


16. feature/search/src/test/kotlin/com/waffiq/bazz_movies/feature/search/ui/SearchAdapterTest.kt 🧪 Tests +0/-208

Remove redundant adapter tests

feature/search/src/test/kotlin/com/waffiq/bazz_movies/feature/search/ui/SearchAdapterTest.kt


17. feature/search/src/test/kotlin/com/waffiq/bazz_movies/feature/search/utils/SearchHelperTest.kt 🧪 Tests +26/-0

Add profile image source utility tests

feature/search/src/test/kotlin/com/waffiq/bazz_movies/feature/search/utils/SearchHelperTest.kt


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Apr 4, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. dateOf skips formatting🐞 Bug ≡ Correctness
Description
DetailDataUtils.dateOf() returns the first non-blank date string without formatting or validation,
yet DetailUIManager now uses it for tvYearReleased, so raw/invalid dates can be displayed
instead of the app’s standard formatted output or the "N/A" fallback.
Code

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt[R123-134]

+  private val Dateable.displayDate: String?
+    get() = listOf(
+      releaseDate,
+      firstAirDate,
+    ).firstOrNull { !it.isNullOrBlank() }
+
+  /**
+   * Provides formatted date for UI.
+   *
+   * @return date if available, otherwise a fallback text.
+   */
+  fun Context.dateOf(item: Dateable): String = item.displayDate ?: getString(not_available)
Evidence
dateOf() directly returns displayDate (raw releaseDate/firstAirDate) and never calls
DateFormatter.dateFormatterStandard, while releaseDateHandler() still uses
dateFormatterStandard() and falls back to not_available when formatting fails. The detail screen
switched from dateFormatterStandard(...) to dateOf(...), changing what is shown to the user.

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt[54-65]
core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt[123-135]
feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt[236-243]
core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DateFormatter.kt[16-59]
core/utils/src/test/kotlin/com/waffiq/bazz_movies/core/utils/DateFormatterTest.kt[18-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`DetailDataUtils.dateOf()` claims to provide a formatted date for UI, but it currently returns the raw `releaseDate`/`firstAirDate` string and does not validate invalid formats. `DetailUIManager` now uses `dateOf()` for `tvYearReleased`, which changes user-visible output and can surface invalid strings.
### Issue Context
There is already an established formatting/validation path via `DateFormatter.dateFormatterStandard(...)` (used by `releaseDateHandler`). `dateOf()` should align with that behavior.
### Fix Focus Areas
- core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt[123-135]
- feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt[236-243]
### What to change
- In `dateOf(item: Dateable)`, apply `dateFormatterStandard` to the chosen date string and return `not_available` when formatting yields blank.
- Consider aligning the date priority with `releaseDateHandler` (currently `firstAirDate` first) if that is the intended logic across the app.
- Add/extend tests for `dateOf()` to cover invalid date strings and ensure it returns the fallback text.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Blank genre fallback🐞 Bug ≡ Correctness
Description
GenreHelper.getGenre() returns transformListGenreIdsToJoinName() for any non-empty list, but
unknown IDs are mapped to empty strings and filtered out, so callers can receive "" instead of the
expected "N/A" fallback.
Code

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelper.kt[R69-74]

+  fun Context.getGenre(data: List<Int>?): String =
+    if (data.isNullOrEmpty()) {
+      getString(not_available)
+    } else {
+      transformListGenreIdsToJoinName(data)
+    }
Evidence
getGenreName() returns orEmpty() for unknown IDs, and the transformer filters empty strings;
when all IDs are unknown, joinToString returns an empty string. getGenre() only checks for
null/empty input list and does not handle the empty-result case.

core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelper.kt[49-74]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Context.getGenre(data)` can return an empty string when `data` is non-empty but contains only unknown genre IDs. This leads to blank UI instead of a consistent fallback.
### Issue Context
`transformListGenreIdsToJoinName()` filters out unknown genre names (empty strings) before joining.
### Fix Focus Areas
- core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/GenreHelper.kt[49-74]
### What to change
- Compute `val result = transformListGenreIdsToJoinName(data)` and return `getString(not_available)` when `result.isBlank()`.
- Add a test case covering `getGenre(listOf(99999))` (or any unknown ID) expecting `"N/A"`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Backdrop flag misnamed🐞 Bug ⚙ Maintainability
Description
MediaHelper.isBackdropAvailable returns true when the backdrop is missing (null/empty/"N/A"),
but the name implies the opposite, making current usage misleading and likely to cause inverted UI
logic when reused elsewhere.
Code

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[R98-100]

+  val Imageble.isBackdropAvailable: Boolean
+    get() = backdropPath.isNullOrEmpty() || backdropPath == NOT_AVAILABLE
+
Evidence
The property definition returns true on missing/NOT_AVAILABLE values, and DetailUIManager assigns
it to tvBackdropNotFound.isVisible, confirming it actually represents a "missing" state despite
being named "available".

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[98-100]
feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt[215-227]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`isBackdropAvailable` currently evaluates to `true` when the backdrop is *not* available, which is a semantic trap.
### Issue Context
It is used to control a "not found" view’s visibility, so the current logic is functionally correct for that use, but the naming is inverted.
### Fix Focus Areas
- feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[98-100]
- feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/ui/manager/DetailUIManager.kt[215-227]
### What to change
- Either:
- Rename to `isBackdropMissing` / `shouldShowBackdropNotFound`, keeping current logic, OR
- Invert the logic so `isBackdropAvailable` means what it says, and update call sites accordingly.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Builds URL with N/A🐞 Bug ≡ Correctness
Description
MediaHelper.backdropOriginalUrl can build TMDB_IMG_LINK_BACKDROP_ORIGINAL + "N/A" when
backdropPath is the sentinel value and posterPath is valid, preventing poster fallback and
causing failed image loads.
Code

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[R82-93]

+  val Imageble.backdropOriginalUrl: String?
+    get() = when {
+      backdropPath == NOT_AVAILABLE && posterPath == NOT_AVAILABLE -> null
+
+      !backdropPath.isNullOrBlank() ->
+        TMDB_IMG_LINK_BACKDROP_ORIGINAL + backdropPath
+
+      !posterPath.isNullOrBlank() ->
+        TMDB_IMG_LINK_POSTER_W500 + posterPath
+
+      else -> null
+    }
Evidence
NOT_AVAILABLE is defined as the literal string "N/A", and the database mapper explicitly writes
backdropPath ?: NOT_AVAILABLE/posterPath ?: NOT_AVAILABLE, so the sentinel can commonly reach
the UI layer. backdropOriginalUrl only special-cases when both backdrop and poster are
NOT_AVAILABLE; otherwise it treats a single "N/A" as non-blank and constructs a URL with it.

feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[82-93]
core/common/src/main/kotlin/com/waffiq/bazz_movies/core/common/utils/Constants.kt[1-10]
core/common/src/main/kotlin/com/waffiq/bazz_movies/core/common/utils/Constants.kt[30-34]
core/database/src/main/kotlin/com/waffiq/bazz_movies/core/database/utils/DatabaseMapper.kt[13-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`backdropOriginalUrl` may build an invalid TMDB URL when either `backdropPath` or `posterPath` equals the sentinel string `NOT_AVAILABLE` ("N/A"). This prevents proper fallback (e.g., to poster) and triggers unnecessary failed network/image decoding work.
### Issue Context
Other helpers (e.g., `posterUrl`) already exclude `NOT_AVAILABLE` explicitly.
### Fix Focus Areas
- feature/detail/src/main/kotlin/com/waffiq/bazz_movies/feature/detail/utils/helpers/MediaHelper.kt[82-93]
### What to change
- Update `backdropOriginalUrl` conditions to treat `NOT_AVAILABLE` as unavailable per-field, e.g.:
- Use backdrop only when `backdropPath` is not blank and `backdropPath != NOT_AVAILABLE`
- Else use poster only when `posterPath` is not blank and `posterPath != NOT_AVAILABLE`
- Else return null
- Add a test case covering `backdropPath = NOT_AVAILABLE` with a valid `posterPath` to ensure it falls back to poster URL rather than building an ".../originalN/A" URL.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Apr 4, 2026

DeepSource Code Review

We reviewed changes in fdf7a24...2eb774a on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Coverage  

Code Review Summary

Analyzer Status Updated (UTC) Details
Kotlin Apr 5, 2026 12:40p.m. Review ↗
Test coverage Apr 5, 2026 1:05p.m. Review ↗

Code Coverage Summary

Language Line Coverage (New Code) Line Coverage (Overall)
Aggregate
100%
98.8%
Kotlin
100%
98.8%

➟ Additional coverage metrics may have been reported. See full coverage report ↗

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented Apr 4, 2026

Not up to standards ⛔

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🔴 Metrics 14 complexity · 2 duplication

Metric Results
Complexity 14 (≤ 20 complexity)
Duplication ⚠️ 2 (≤ 1 duplication)

View in Codacy

🟢 Coverage 100.00% diff coverage · -0.01% coverage variation

Metric Results
Coverage variation -0.01% coverage variation (-1.00%)
Diff coverage 100.00% diff coverage (80.00%)

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (e9d6bc2) 6277 6227 99.20%
Head commit (2eb774a) 6290 (+13) 6239 (+12) 99.19% (-0.01%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#551) 100 100 100.00%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

TIP This summary will be updated as you push new changes. Give us feedback

Comment thread core/utils/src/main/kotlin/com/waffiq/bazz_movies/core/utils/DetailDataUtils.kt Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 4, 2026

Qodana Community for JVM

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked
☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@qltysh
Copy link
Copy Markdown

qltysh Bot commented Apr 4, 2026

All good ✅

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 5, 2026

@waffiqaziz waffiqaziz merged commit 5a07726 into main Apr 5, 2026
42 of 43 checks passed
@waffiqaziz waffiqaziz deleted the dev-refactor branch April 5, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Change implementation or structure without changing behavior. Review effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant