Skip to content

Conversation

@Cd16d
Copy link
Owner

@Cd16d Cd16d commented Feb 7, 2026

Motivation

  • Make the cast manager a singleton service available across modules and expose an opt-out toggle in settings so casting can be disabled by users.
  • Use the proprietary product flavor as the default build variant while keeping the libre flavor available.

Description

  • Set proprietary as the default variant in app/phone/build.gradle.kts and keep libre as a second flavor.
  • Add a persistent preference playerCastEnabled in settings/src/main/java/.../AppPreferences.kt defaulting to true.
  • Add UI strings for the new settings entries in settings/src/main/res/values/strings.xml and wire a PreferenceSwitch into the player settings in SettingsViewModel.kt to surface the toggle.
  • Introduce a core CastManager interface in player/core and provide an application singleton implementation DefaultCastManager in app/phone that reads/writes playerCastEnabled, plus a Hilt CastModule to bind the singleton.

Testing

  • No automated tests were executed as part of this change.

Codex Task

Summary by Sourcery

Introduce a global cast management service controlled by a new user setting and switch the Android phone app to use the proprietary build flavor by default.

New Features:

  • Add a casting settings section with a toggle to enable or disable casting in the player.
  • Introduce a core CastManager interface with an application-wide singleton implementation wired via Hilt.

Enhancements:

  • Persist the casting enabled state in shared preferences so it can be read and updated across modules.

Build:

  • Set the Android phone app's default product flavor to proprietary while keeping the libre flavor available.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 7, 2026

Reviewer's Guide

Introduces a singleton CastManager service wired via Hilt, exposes a user-facing toggle to enable/disable casting through settings, and changes the Android build configuration to use the proprietary product flavor as the default while keeping libre as an additional flavor.

Sequence diagram for toggling casting and reading CastManager state

sequenceDiagram
    actor User
    participant SettingsUI
    participant SettingsViewModel
    participant AppPreferences
    participant SharedPreferences
    participant SomePlayerComponent
    participant CastManager

    User->>SettingsUI: Toggle cast switch
    SettingsUI->>SettingsViewModel: onCastToggle(enabled)
    SettingsViewModel->>AppPreferences: setValue(playerCastEnabled, enabled)
    AppPreferences->>SharedPreferences: putBoolean(pref_player_cast_enabled, enabled)
    SharedPreferences-->>AppPreferences: persist_success
    AppPreferences-->>SettingsViewModel: completion
    SettingsViewModel-->>SettingsUI: update_switch_state

    SomePlayerComponent->>CastManager: isCastingEnabled
    CastManager-->>SomePlayerComponent: Boolean
Loading

Class diagram for CastManager singleton and preferences integration

classDiagram
    class CastManager {
        <<interface>>
        +Boolean isCastingEnabled
        +setCastingEnabled(enabled Boolean)
    }

    class DefaultCastManager {
        +DefaultCastManager(appPreferences AppPreferences)
        +Boolean isCastingEnabled
        +setCastingEnabled(enabled Boolean)
        -appPreferences AppPreferences
    }

    class AppPreferences {
        +SharedPreferences sharedPreferences
        +Preference playerPipGesture
        +Preference playerCastEnabled
        +Preference downloadOverMobileData
        +Preference downloadWhenRoaming
        +getValue(preference Preference) Boolean
        +setValue(preference Preference, value Boolean)
    }

    class Preference {
        +String key
        +Boolean defaultValue
    }

    class CastModule {
        <<HiltModule>>
        +bindCastManager(impl DefaultCastManager) CastManager
    }

    CastManager <|.. DefaultCastManager
    AppPreferences "1" --> "*" Preference : uses
    DefaultCastManager --> AppPreferences : depends_on
    CastModule ..> CastManager : binds
    CastModule ..> DefaultCastManager : implementation
Loading

File-Level Changes

Change Details Files
Expose a user-facing setting to enable or disable casting in the player.
  • Add a new boolean preference key playerCastEnabled with default true in the shared AppPreferences domain model.
  • Introduce a new "Casting" preference group in SettingsViewModel under player settings, with a PreferenceSwitch bound to the new preference and scoped to phone devices.
  • Add corresponding UI strings for the casting section, toggle label, and description in the settings resources.
settings/src/main/java/dev/jdtech/jellyfin/settings/domain/AppPreferences.kt
settings/src/main/java/dev/jdtech/jellyfin/settings/presentation/settings/SettingsViewModel.kt
settings/src/main/res/values/strings.xml
Add a core CastManager abstraction and a singleton app-level implementation backed by preferences.
  • Define a CastManager interface in the player core domain module exposing an isCastingEnabled property and a mutator method.
  • Implement DefaultCastManager in the app/phone module that reads and writes the playerCastEnabled preference via AppPreferences.
  • Register DefaultCastManager as a @singleton binding for the CastManager interface using a Hilt module installed in the SingletonComponent.
player/core/src/main/java/dev/jdtech/jellyfin/player/core/domain/CastManager.kt
app/phone/src/main/java/dev/jdtech/jellyfin/cast/DefaultCastManager.kt
app/phone/src/main/java/dev/jdtech/jellyfin/di/CastModule.kt
Change the app/phone build configuration to default to the proprietary flavor while preserving the libre flavor.
  • Modify the productFlavors block to register proprietary as the default flavor in the variant dimension.
  • Reintroduce/register libre as a secondary flavor in the same dimension without default status.
app/phone/build.gradle.kts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Consider exposing CastManager state as a reactive stream (e.g., Flow/State) rather than a simple boolean getter so that UI or services depending on casting can observe changes without polling SharedPreferences on each access.
  • In SettingsViewModel, you’re wiring the casting toggle directly to AppPreferences.playerCastEnabled; if CastManager is intended as the central abstraction, you may want to route writes/reads through it to avoid future duplication of casting logic across modules.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider exposing `CastManager` state as a reactive stream (e.g., Flow/State) rather than a simple boolean getter so that UI or services depending on casting can observe changes without polling `SharedPreferences` on each access.
- In `SettingsViewModel`, you’re wiring the casting toggle directly to `AppPreferences.playerCastEnabled`; if `CastManager` is intended as the central abstraction, you may want to route writes/reads through it to avoid future duplication of casting logic across modules.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant