Skip to content

feat: Add configurable personal rating styles - #806

Open
PabloLec wants to merge 2 commits into
Moonfin-Client:mainfrom
PabloLec:feature/personal-ratings
Open

feat: Add configurable personal rating styles#806
PabloLec wants to merge 2 commits into
Moonfin-Client:mainfrom
PabloLec:feature/personal-ratings

Conversation

@PabloLec

Copy link
Copy Markdown

Summary

This PR adds configurable personal ratings to movie detail screens.

Users can keep the existing like/dislike controls or choose a five-star or numeric rating style. Ratings are stored in the media server's native user data, so the same rating can be retrieved by other clients connected as that user.

This is intended as a foundation for broader personal rating support in Moonfin. Future work could optionally synchronize ratings with external services such as TMDb, Trakt, Simkl, or Letterboxd where a suitable API is available. Personal ratings could also be displayed alongside the existing public rating sources on detail screens.

Like/dislike remains the default, preserving the existing experience for current users.

This PR does not add Moonbase storage, a local rating database, or external provider synchronization

This PR includes the regenerated localization files for all supported locales, which accounts for most of the changed files, untranslated strings currently fall back to English. Please let me know if this matches the expected localization workflow or if these generated files should be handled differently.

Related Issues

  • Related to #

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Performance improvement
  • UI/UX update
  • Documentation update
  • Build/CI change
  • Other (describe):

Changes Made

  • Added support for reading personal Rating and Likes values from server user data.
  • Added three configurable personal rating styles:
    • Like / dislike
    • Five stars, including half-star values
    • Numeric score out of 10
  • Added the preference under Settings → Personalization → Details Screen.
  • Added a rating action and adaptive dialog to movie detail screens.
  • Added keyboard and D-pad friendly controls.
  • Added a separate action for clearing an existing rating.
  • Preserved the existing like/dislike behavior.
  • Added numeric rating updates for Jellyfin and Emby.
  • Added optimistic updates, duplicate-submission protection, server refresh after saving, and rollback with user-visible feedback on failure.
  • Explicitly requested UserData when loading Jellyfin item details so saved ratings are restored when an item is reopened.
  • Added tests covering model parsing, API requests, preferences, mutations, rollback behavior, dialog controls, and focus restoration.
  • Added the English localization source strings and regenerated the Flutter localization files with Flutter 3.44.1.

Rating Behavior

The selected style only changes how a rating is displayed and entered. Switching styles does not rewrite an existing server value.

Like / dislike

The existing thumbs behavior is preserved.

Users can:

  • Like an item
  • Dislike an item
  • Clear the current rating

If an existing numeric rating is displayed as thumbs, Moonfin uses the server-provided Likes value rather than applying a separate client-side interpretation.

Five stars

Star ratings support half-star values and are converted to the server's 0–10 rating scale.

Examples:

  • 2.5 / 5 is stored as 5 / 10
  • 4 / 5 is stored as 8 / 10
  • 4.5 / 5 is stored as 9 / 10

Changing to the star presentation does not round or update an existing rating until the user explicitly saves a new value.

Numeric

Numeric ratings use the server's 0–10 scale directly.

The dialog uses increment and decrement controls designed to remain usable with touch, keyboard, and TV remotes.

Server Behavior

Jellyfin

  • Numeric ratings are written through:

    POST /UserItems/{itemId}/UserData

    with a minimal body containing only the new rating:

    {
      "Rating": 8.5
    }
  • Existing thumbs ratings continue to use Jellyfin's dedicated like/dislike endpoint.

  • Like maps to Jellyfin's native rating value of 10.

  • Dislike maps to Jellyfin's native rating value of 1.

  • Clearing a rating continues to use:

    DELETE /UserItems/{itemId}/Rating
  • Numeric ratings use the Likes interpretation returned by Jellyfin.

Emby

  • Existing like/dislike behavior is preserved.
  • Numeric ratings are written through Emby's per-user item data endpoint.
  • The same UI styles are available when the active server reports numeric rating support.
  • No Jellyfin-specific endpoint or rating assumption is used for Emby mutations.

Offline items

Numeric rating mutations are not exposed while operating through the offline API stubs.

Preferences

The selected presentation style is stored locally for the current Moonfin user and server.

The rating itself remains stored in Jellyfin or Emby user data and is therefore independent from this presentation preference.

Cross-device synchronization of the presentation preference could be added separately through Moonbase without changing the stored ratings or the rating API introduced here.

Platform

  • Android
  • iOS
  • tvOS
  • Web
  • macOS
  • Windows
  • Linux
  • All / Shared code

Testing

  • Tested on emulator / simulator
  • Tested on physical device
  • Manual testing completed
  • Not tested (explain why):

Manual testing was completed on Web and Linux.

Test Steps

  1. Open a movie without an existing personal rating.
  2. Open Settings → Personalization → Details Screen.
  3. Select each available personal rating style.
  4. Verify that like/dislike mode supports like, dislike, and clear.
  5. Verify that star mode supports half-star values and clear.
  6. Verify that numeric mode supports increment, decrement, save, and clear.
  7. Change the presentation style without submitting another rating and confirm that the stored value remains unchanged.
  8. Restart Moonfin, reopen the movie, and confirm that the saved rating is restored from server user data.
  9. Verify keyboard and D-pad navigation in the rating dialog.
  10. Simulate a failed save and confirm that the previous state is restored and an error is shown.

Screenshots

(sorry for the mostly french UI)

Settings menu

details_menu

Like / dislike

Not rated
like_dislike_not_rated
Rated
like_dislike_rated

Stars

Not rated
stars_not_rated
Rating
stars_rating
Rated
stars_rated
stars_rated_2

Numeric

Not rated
numeric_not_rated
Rating
numeric_rating
Rated
numeric_rated

Future Work

This PR deliberately keeps the first implementation limited to native media-server ratings.

Possible follow-up work includes:

  • Synchronizing ratings with connected TMDb, Trakt, Simkl, or Letterboxd accounts.
  • Importing existing ratings from supported external services.
  • Displaying the user's personal rating alongside Moonfin's existing public rating sources.
  • Synchronizing the selected presentation style through Moonbase.
  • Extending the rating action to additional media types.
  • Exploring server-side aggregate ratings across multiple media-server users, subject to suitable privacy, permission, and server API support.

None of these integrations or aggregation features are included in this PR.

Known Limitations

  • The initial UI is limited to movie detail screens.
  • The selected presentation style is currently device-local.
  • No external rating service is connected.
  • Moonfin does not preserve a rating independently after the underlying server item has been fully removed.
  • Aggregate ratings across multiple Jellyfin or Emby users are not currently available.

Checklist

  • Code builds successfully
  • Code follows project style and conventions
  • No unnecessary commented-out code
  • No new warnings introduced

@RadicalMuffinMan

Copy link
Copy Markdown
Contributor

Don't think I'm ignoring your PR, I really like it, just waiting until after the hotfix to add it, thank you.

@PabloLec

Copy link
Copy Markdown
Author

Don't think I'm ignoring your PR, I really like it, just waiting until after the hotfix to add it, thank you.

No worries, there’s no rush 😁 By the way, feel free to let me know how you usually prefer to handle localization files. I left the auto-generated files in this PR, but obviously they add quite a lot of noise.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants