-
-
Notifications
You must be signed in to change notification settings - Fork 84
feat: Display specials #711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for implementing this. I added a few comments let me know if anything is unclear.
I don't have any special features so not fully able to test it. But the code looks fine logic wise.
| @MappableClass() | ||
| class SpecialFeatureModel extends ItemStreamModel with SpecialFeatureModelMappable { | ||
| final List<Chapter> chapters; | ||
| final ItemLocation? location; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unused probably better to remove it.
| static List<SpecialFeatureModel> specialFeaturesFromDto(List<dto.BaseItemDto>? dto, Ref ref) { | ||
| return dto?.map((e) => SpecialFeatureModel.fromBaseDto(e, ref)).toList() ?? []; | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add the newline as well. So we can keep consistent formatting.
lib/providers/service_provider.dart
Outdated
| try { | ||
| return api.itemsItemIdSpecialFeaturesGet(itemId: itemId, userId: account?.id); | ||
| } catch (e) { | ||
| return Response(http.Response("", 400), []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any errors here will be obfuscated because we throw away whatever the exception is telling us.
Remove the try{} catch{}. So we can monitor the original response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that we shouldnt swallow the exception here. But I do think the current callers should catch them and emit a log if there is a problem since in this context a failure should not stop the application.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. Currently the handling of errors is a bit of a mess of my making.
Lets just leave it as is without the try/catch same as most of the other calls. I will have to come up with a proper solution when I can find the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I already moved the try catch before I saw this. Let me know if you want me to remove it anyways.
| List<SpecialFeatureModel> get specialFeatures { | ||
| return widget.specialFeatures; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| List<SpecialFeatureModel> get specialFeatures { | |
| return widget.specialFeatures; | |
| } | |
| List<SpecialFeatureModel> specialFeatures = widget.specialFeatures; |
This can be moved to the build part of the widget. After that make the widget stateless as there is no state we need to maintain.
| final String? label; | ||
| final ValueChanged<SpecialFeatureModel> playSpecialFeature; | ||
| final EdgeInsets contentPadding; | ||
| final Function(VoidCallback action, SpecialFeatureModel specialFeatureModel)? onSpecialFeatureTap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| final Function(VoidCallback action, SpecialFeatureModel specialFeatureModel)? onSpecialFeatureTap; | |
| final Function(SpecialFeatureModel specialFeatureModel)? onSpecialFeatureTap; |
Why does this take another VoidCallback as argument? I would suggest to only return the SpecialFeatureModel.
| startIndex: null, | ||
| items: specialFeatures, | ||
| itemBuilder: (context, index) { | ||
| final specialFeature = specialFeatures[index]; | ||
| final tag = UniqueKey(); | ||
| return SpecialFeaturePoster( | ||
| specialFeature: specialFeature, | ||
| heroTag: tag, | ||
| blur: false, | ||
| onTap: widget.onSpecialFeatureTap != null | ||
| ? () { | ||
| widget.onSpecialFeatureTap?.call( | ||
| () { | ||
| specialFeature.play(context, ref); | ||
| }, | ||
| specialFeature, | ||
| ); | ||
| } | ||
| : () { | ||
| specialFeature.play(context, ref); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| startIndex: null, | |
| items: specialFeatures, | |
| itemBuilder: (context, index) { | |
| final specialFeature = specialFeatures[index]; | |
| final tag = UniqueKey(); | |
| return SpecialFeaturePoster( | |
| specialFeature: specialFeature, | |
| heroTag: tag, | |
| blur: false, | |
| onTap: widget.onSpecialFeatureTap != null | |
| ? () { | |
| widget.onSpecialFeatureTap?.call( | |
| () { | |
| specialFeature.play(context, ref); | |
| }, | |
| specialFeature, | |
| ); | |
| } | |
| : () { | |
| specialFeature.play(context, ref); | |
| }, | |
| onTap: widget.onSpecialFeatureTap != null | |
| ? () => widget.onSpecialFeatureTap?.call( | |
| specialFeature, | |
| ) | |
| : () => specialFeature.play(context, ref), |
Ok now we know why there was a action. But I'm not sure why that behaviour is there.
I would expect the function to be called if not null and we then supply the tapped specialFeature. Where we can then do whatever action needed in the details screens.
It's ok to fallback to a "default" action, but when the function has a override it should not still call the "default" action.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior is consistent with the existing behavior from EpisodePosters widget. I don't really understand the concern, it is up to the caller to invoke the default action (in this case play) using the callback provided in onSpecialFeatureTap if they wish to.
From what I understand from looking at the code, onSpecialFeatureTap provides a hook to callers to change the behavior of the tap action. onSpecialFeatureTap also provides a callback to the default action so that the caller can use it if they still want to perform the default actions during the customized logic.
This all makes sense to me and is what was already implemented in EpisodePosters so I am keeping it like this for now. But please correct me if I am missing something and I will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more that I like to explicitly know what "action" is.
This makes the code just a little bit less readable because we have to dive into the widget itself to see what action actually does.
I know it also happens in the EpisodePosters but I don't like it there either, I should probably remove it there as well just did not get to that yet.
So it's fine to leave it as is, this works perfectly fine. But I would prefer the callback to be more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made some changes to hopefully make it more readable. If you still don't like it I will take your recommended solution instead.
PartyDonut
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, thanks for implementing the changes.
Pull Request Description
Adds a special features row to show details and season details screens, similar to the official jellyfin client. Unfortunately, due to how the special features API is set up, it is really difficult to group them by season in the show screen without making a bunch of API calls.
Issue Being Fixed
Resolves #632
Screenshots / Recordings
show screen:
season screen:
Checklist