Skip to content

Commit

Permalink
Hide spoilers in calendar and upcomping section by default (#1194)
Browse files Browse the repository at this point in the history
* chore(models/media): change order of attributes

* refactor(frontend): remove useless extra component

* chore(frontend): change display of watch providers section

* feat(frontend): move review scale out of grid

* feat(migrations): add new preference for showing spoilers in calendar

* feat(backend): add preference for showing spoilers in calendar

* feat(backend): respect new preference for spoilers

* feat(frontend): add new preference option

* chore(frontend): adapt to new gql schema

* chore(gql): use spaces for indentation
  • Loading branch information
IgnisDa authored Jan 22, 2025
1 parent 11c8565 commit 17d6131
Show file tree
Hide file tree
Showing 21 changed files with 1,257 additions and 1,222 deletions.
2 changes: 1 addition & 1 deletion apps/frontend/app/routes/_dashboard._index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ const UpComingMedia = ({ um }: { um: CalendarEventPartFragment }) => {

return (
<MetadataDisplayItem
altName={um.episodeName || um.metadataTitle}
altName={um.metadataText}
metadataId={um.metadataId}
noLeftLabel
rightLabel={`${match(um.metadataLot)
Expand Down
42 changes: 17 additions & 25 deletions apps/frontend/app/routes/_dashboard.calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
import type { LoaderFunctionArgs, MetaArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import {
type CalendarEventPartFragment,
MediaLot,
UserCalendarEventsDocument,
type UserCalendarEventsQuery,
Expand Down Expand Up @@ -130,32 +129,25 @@ const CalendarEvent = (props: {
</Stack>
</Group>
<ApplicationGrid>
{props.data.events.map((evt) => (
<DisplayCalendarEvent key={evt.calendarEventId} calEvent={evt} />
{props.data.events.map((calEvent) => (
<MetadataDisplayItem
key={calEvent.calendarEventId}
altName={calEvent.metadataText}
metadataId={calEvent.metadataId}
rightLabel={`${match(calEvent.metadataLot)
.with(
MediaLot.Show,
() =>
`S${calEvent.showExtraInformation?.season}-E${calEvent.showExtraInformation?.episode}`,
)
.with(
MediaLot.Podcast,
() => `EP-${calEvent.podcastExtraInformation?.episode}`,
)
.otherwise(() => "")}`}
/>
))}
</ApplicationGrid>
</Fragment>
);
};

const DisplayCalendarEvent = ({
calEvent,
}: { calEvent: CalendarEventPartFragment }) => {
return (
<MetadataDisplayItem
metadataId={calEvent.metadataId}
altName={calEvent.episodeName || calEvent.metadataTitle}
rightLabel={`${match(calEvent.metadataLot)
.with(
MediaLot.Show,
() =>
`S${calEvent.showExtraInformation?.season}-E${calEvent.showExtraInformation?.episode}`,
)
.with(
MediaLot.Podcast,
() => `EP-${calEvent.podcastExtraInformation?.episode}`,
)
.otherwise(() => "")}`}
/>
);
};
150 changes: 81 additions & 69 deletions apps/frontend/app/routes/_dashboard.settings.preferences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ export default function Page() {
"disableReviews",
"disableWatchProviders",
"persistQueries",
"showSpoilersInCalendar",
] as const
).map((name) => (
<Switch
Expand Down Expand Up @@ -315,88 +316,99 @@ export default function Page() {
)
.with(
"persistQueries",
() => "Persist queries in the URL",
() =>
"Persist queries in the URL so that you look at the same data next time you visit it",
)
.with(
"showSpoilersInCalendar",
() =>
"Show episode title in calendar and upcoming section which might contain spoilers",
)
.exhaustive()}
/>
))}
<Select
size="xs"
disabled={!!isEditDisabled}
label="Scale used for rating in reviews"
defaultValue={userPreferences.general.reviewScale}
data={Object.values(UserReviewScale).map((c) => ({
value: c,
label: startCase(snakeCase(c)),
}))}
onChange={(val) => {
if (val) {
updatePreference((draft) => {
draft.general.reviewScale = val as UserReviewScale;
});
}
}}
/>
</SimpleGrid>
<Input.Wrapper
label="Grid packing"
description="Display size for library user interface elements"
>
<SegmentedControl
mt="xs"
fullWidth
disabled={!!isEditDisabled}
defaultValue={userPreferences.general.gridPacking}
data={Object.values(GridPacking).map((c) => ({
value: c,
label: startCase(snakeCase(c)),
}))}
onChange={(val) => {
if (val) {
updatePreference((draft) => {
draft.general.gridPacking = val as GridPacking;
});
}
}}
/>
</Input.Wrapper>
<Stack>
<Stack gap="xs">
<Input.Wrapper
label="Review scale"
description="Scale you want to use for reviews"
>
<SegmentedControl
mt="xs"
fullWidth
disabled={!!isEditDisabled}
defaultValue={userPreferences.general.reviewScale}
data={Object.values(UserReviewScale).map((c) => ({
value: c,
label: startCase(snakeCase(c)),
}))}
onChange={(val) => {
if (val) {
updatePreference((draft) => {
draft.general.reviewScale = val as UserReviewScale;
});
}
}}
/>
</Input.Wrapper>
<Input.Wrapper
label="Grid packing"
description="Display size for library user interface elements"
>
<SegmentedControl
mt="xs"
fullWidth
disabled={!!isEditDisabled}
defaultValue={userPreferences.general.gridPacking}
data={Object.values(GridPacking).map((c) => ({
value: c,
label: startCase(snakeCase(c)),
}))}
onChange={(val) => {
if (val) {
updatePreference((draft) => {
draft.general.gridPacking = val as GridPacking;
});
}
}}
/>
</Input.Wrapper>
</Stack>
<Stack gap="sm">
<Title order={3}>Watch providers</Title>
{Object.values(MediaLot).map((lot) => {
const watchProviders =
changingUserPreferences.value.general.watchProviders;
const existingValues =
watchProviders.find((wp) => wp.lot === lot)?.values || [];
return (
<Stack key={lot} gap={4}>
<Text>{changeCase(lot)}</Text>
<TagsInput
disabled={!!isEditDisabled}
defaultValue={existingValues}
placeholder="Enter more providers"
onChange={(val) => {
if (val) {
const newWatchProviders =
Array.from(watchProviders);
let existingMediaLot = newWatchProviders.find(
(wp) => wp.lot === lot,
);
if (!existingMediaLot) {
existingMediaLot = {
values: val,
lot: lot as MediaLot,
};
newWatchProviders.push(existingMediaLot);
} else {
existingMediaLot.values = val;
}
updatePreference((draft) => {
draft.general.watchProviders = newWatchProviders;
});
<TagsInput
key={lot}
label={changeCase(lot)}
disabled={!!isEditDisabled}
defaultValue={existingValues}
placeholder="Enter more providers"
onChange={(val) => {
if (val) {
const newWatchProviders = Array.from(watchProviders);
let existingMediaLot = newWatchProviders.find(
(wp) => wp.lot === lot,
);
if (!existingMediaLot) {
existingMediaLot = {
values: val,
lot: lot as MediaLot,
};
newWatchProviders.push(existingMediaLot);
} else {
existingMediaLot.values = val;
}
}}
/>
</Stack>
updatePreference((draft) => {
draft.general.watchProviders = newWatchProviders;
});
}
}}
/>
);
})}
</Stack>
Expand Down
2 changes: 2 additions & 0 deletions crates/migrations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod m20240904_create_monitored_entity;
mod m20241004_create_application_cache;
mod m20241214_create_user_notification;
mod m20250118_is_v8_migration;
mod m20250122_changes_for_issue_1188;

pub use m20230404_create_user::User as AliasedUser;
pub use m20230410_create_metadata::Metadata as AliasedMetadata;
Expand Down Expand Up @@ -75,6 +76,7 @@ impl MigratorTrait for Migrator {
Box::new(m20241004_create_application_cache::Migration),
Box::new(m20241214_create_user_notification::Migration),
Box::new(m20250118_is_v8_migration::Migration),
Box::new(m20250122_changes_for_issue_1188::Migration),
]
}
}
22 changes: 22 additions & 0 deletions crates/migrations/src/m20250122_changes_for_issue_1188.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let db = manager.get_connection();
db.execute_unprepared(
r#"
UPDATE "user" SET "preferences" = jsonb_set("preferences", '{general,show_spoilers_in_calendar}', 'false');
"#,
)
.await?;
Ok(())
}

async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
Ok(())
}
}
5 changes: 2 additions & 3 deletions crates/models/media/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1394,14 +1394,13 @@ pub struct CreateReviewCommentInput {
pub struct GraphqlCalendarEvent {
pub date: NaiveDate,
pub metadata_id: String,
pub metadata_title: String,
pub metadata_text: String,
pub metadata_lot: MediaLot,
pub calendar_event_id: String,
pub episode_name: Option<String>,
pub metadata_image: Option<String>,
pub show_extra_information: Option<SeenShowExtraInformation>,
pub podcast_extra_information: Option<SeenPodcastExtraInformation>,
pub anime_extra_information: Option<SeenAnimeExtraInformation>,
pub podcast_extra_information: Option<SeenPodcastExtraInformation>,
}

#[derive(Debug, Serialize, Deserialize, SimpleObject, Clone, Default)]
Expand Down
18 changes: 10 additions & 8 deletions crates/models/user/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,6 @@ pub struct UserGeneralPreferences {
pub disable_reviews: bool,
#[educe(Default = true)]
pub persist_queries: bool,
#[educe(Default(expression = vec![UserGeneralWatchProvider {
lot: MediaLot::Movie,
values: MOVIE_WATCH_PROVIDERS
.into_iter()
.map(|s| s.to_owned())
.collect(),
}]))]
pub watch_providers: Vec<UserGeneralWatchProvider>,
#[educe(Default = GridPacking::Dense)]
pub grid_packing: GridPacking,
#[educe(Default = UserReviewScale::OutOfHundred)]
Expand All @@ -448,7 +440,17 @@ pub struct UserGeneralPreferences {
#[educe(Default = false)]
pub disable_integrations: bool,
#[educe(Default = false)]
pub show_spoilers_in_calendar: bool,
#[educe(Default = false)]
pub disable_navigation_animation: bool,
#[educe(Default(expression = vec![UserGeneralWatchProvider {
lot: MediaLot::Movie,
values: MOVIE_WATCH_PROVIDERS
.into_iter()
.map(|s| s.to_owned())
.collect(),
}]))]
pub watch_providers: Vec<UserGeneralWatchProvider>,
#[educe(Default(expression = vec![
UserGeneralDashboardElement {
num_elements: Some(8),
Expand Down
14 changes: 9 additions & 5 deletions crates/services/miscellaneous/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,8 @@ ORDER BY RANDOM() LIMIT 10;
)
.order_by(Alias::new("date"), Order::Asc)
.to_owned();
let user_preferences = user_by_id(&user_id, &self.0).await?.preferences;
let show_spoilers_in_calendar = user_preferences.general.show_spoilers_in_calendar;
let all_events = CalEvent::find_by_statement(self.get_db_stmt(stmt))
.all(&self.0.db)
.await?;
Expand All @@ -798,26 +800,29 @@ ORDER BY RANDOM() LIMIT 10;
date: evt.date,
metadata_lot: evt.m_lot,
calendar_event_id: evt.id,
metadata_title: evt.m_title,
metadata_text: evt.m_title,
metadata_id: evt.metadata_id,
..Default::default()
};
let mut image = None;
let mut title = None;

if let Some(s) = evt.metadata_show_extra_information {
if let Some(sh) = evt.m_show_specifics {
if let Some((_, ep)) = get_show_episode_by_numbers(&sh, s.season, s.episode) {
image = ep.poster_images.first().cloned();
title = Some(ep.name.clone());
if show_spoilers_in_calendar {
calc.metadata_text = ep.name.clone();
}
}
}
calc.show_extra_information = Some(s);
} else if let Some(p) = evt.metadata_podcast_extra_information {
if let Some(po) = evt.m_podcast_specifics {
if let Some(ep) = get_podcast_episode_by_number(&po, p.episode) {
image = ep.thumbnail.clone();
title = Some(ep.title.clone());
if show_spoilers_in_calendar {
calc.metadata_text = ep.title.clone();
}
}
};
calc.podcast_extra_information = Some(p);
Expand All @@ -830,7 +835,6 @@ ORDER BY RANDOM() LIMIT 10;
first_metadata_image_as_url(&evt.m_images, &self.0.file_storage_service).await
}
calc.metadata_image = image;
calc.episode_name = title;
events.push(calc);
}
Ok(events)
Expand Down
Loading

0 comments on commit 17d6131

Please sign in to comment.