diff --git a/src/features/comment/CommentSort.tsx b/src/features/comment/CommentSort.tsx index e14d64e4b..ebbb4a87d 100644 --- a/src/features/comment/CommentSort.tsx +++ b/src/features/comment/CommentSort.tsx @@ -36,7 +36,7 @@ const BUTTONS: ActionSheetButton[] = COMMENT_SORTS.map( ); interface CommentSortProps { - sort: CommentSortType; + sort: CommentSortType | undefined; setSort: (sort: CommentSortType) => void; } @@ -44,6 +44,8 @@ export default function CommentSort({ sort, setSort }: CommentSortProps) { const [open, setOpen] = useState(false); const { activePageRef } = useContext(AppContext); + if (!sort) return; + return ( <> setOpen(true)}> diff --git a/src/features/feed/sort/feedSortSlice.tsx b/src/features/feed/sort/feedSortSlice.tsx index 6f3e48dfd..8648e24dd 100644 --- a/src/features/feed/sort/feedSortSlice.tsx +++ b/src/features/feed/sort/feedSortSlice.tsx @@ -1,5 +1,5 @@ import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import { ListingType, SortType } from "lemmy-js-client"; +import { CommentSortType, ListingType, SortType } from "lemmy-js-client"; import { db } from "../../../services/db"; import { RootState } from "../../../store"; import { getFeedUrlName } from "../../community/mod/ModActions"; @@ -8,34 +8,54 @@ interface PostSortState { /** * `null`: Loaded from database, but nothing there */ - sortByFeedName: Record; + sortByContextByFeedName: { + posts: Record; + comments: Record; + }; } const initialState: PostSortState = { - sortByFeedName: {}, + sortByContextByFeedName: { + posts: {}, + comments: {}, + }, }; +export type SetSortActionPayload = + | { + feed: FeedSortFeed; + sort: SortType; + context: "posts"; + } + | { + feed: FeedSortFeed; + sort: CommentSortType; + context: "comments"; + }; + export const feedSortSlice = createSlice({ name: "feedSort", initialState, reducers: { - setFeedSort: ( - state, - action: PayloadAction<{ feed: FeedSortFeed; sort: SortType }>, - ) => { + setFeedSort: (state, action: PayloadAction) => { const feedName = serializeFeedName(action.payload.feed); - state.sortByFeedName[feedName] = action.payload.sort; + state.sortByContextByFeedName[action.payload.context][feedName] = + action.payload.sort; - db.setSetting("default_post_sort_by_feed", action.payload.sort, { - community: feedName, - }); + db.setSetting( + getDefaultSortSettingForContext(action.payload.context), + action.payload.sort, + { + community: feedName, + }, + ); }, }, extraReducers: (builder) => { builder.addCase(getFeedSort.fulfilled, (state, action) => { - const { feedName, sort } = action.payload; + const { feedName, sort, context } = action.payload; - state.sortByFeedName[feedName] = sort; + state.sortByContextByFeedName[context][feedName] = sort; }); }, }); @@ -55,23 +75,33 @@ export type FeedSortFeed = export const getFeedSort = createAsyncThunk( "feedSort/getFeedSort", - async (feed: FeedSortFeed) => { + async ({ + feed, + context, + }: { + feed: FeedSortFeed; + context: "posts" | "comments"; + }) => { const feedName = serializeFeedName(feed); const sort = - (await db.getSetting("default_post_sort_by_feed", { + (await db.getSetting(getDefaultSortSettingForContext(context), { community: feedName, - })) ?? null; + })) ?? null; // null = loaded, but not found return { feedName, sort, + context, }; }, ); export const getFeedSortSelectorBuilder = - (feed: FeedSortFeed | undefined) => (state: RootState) => - feed ? state.feedSort.sortByFeedName[serializeFeedName(feed)] : null; + (feed: FeedSortFeed | undefined, context: "posts" | "comments") => + (state: RootState) => + feed + ? state.feedSort.sortByContextByFeedName[context][serializeFeedName(feed)] + : null; function serializeFeedName(feed: FeedSortFeed): string { switch (true) { @@ -83,3 +113,12 @@ function serializeFeedName(feed: FeedSortFeed): string { return feed; } } + +function getDefaultSortSettingForContext(context: "posts" | "comments") { + switch (context) { + case "comments": + return "default_comment_sort_by_feed"; + case "posts": + return "default_post_sort_by_feed"; + } +} diff --git a/src/features/feed/sort/useFeedSort.tsx b/src/features/feed/sort/useFeedSort.tsx index 1d828bb97..99a88958b 100644 --- a/src/features/feed/sort/useFeedSort.tsx +++ b/src/features/feed/sort/useFeedSort.tsx @@ -1,49 +1,68 @@ -import { SortType } from "lemmy-js-client"; +import { CommentSortType, SortType } from "lemmy-js-client"; import { useEffect, useState } from "react"; import { useAppDispatch, useAppSelector } from "../../../store"; import { FeedSortFeed, + SetSortActionPayload, getFeedSort, getFeedSortSelectorBuilder, setFeedSort, } from "./feedSortSlice"; -export default function useFeedSort(feed?: FeedSortFeed | undefined) { +type SortTypeByContext = { + posts: SortType; + comments: CommentSortType; +}; + +export default function useSortByFeed< + Context extends "posts" | "comments", + Sort extends SortTypeByContext[Context], +>(context: Context, feed?: FeedSortFeed | undefined) { const dispatch = useAppDispatch(); - const feedSort = useAppSelector(getFeedSortSelectorBuilder(feed)); + const feedSort = useAppSelector( + getFeedSortSelectorBuilder(feed, context), + ) as Sort; const defaultSort = useAppSelector( - (state) => state.settings.general.posts.sort, - ); + (state) => state.settings.general[context].sort, + ) as Sort; const rememberCommunitySort = useAppSelector( - (state) => state.settings.general.posts.rememberCommunitySort, + (state) => state.settings.general[context].rememberCommunitySort, ); - const [sort, _setSort] = useState( + const [sort, _setSort] = useState( !rememberCommunitySort ? defaultSort : undefined, ); useEffect(() => { - if (!rememberCommunitySort) return; - if (!feed) return; + (async () => { + if (!rememberCommunitySort) return; + if (!feed) return; - dispatch(getFeedSort(feed)); - }, [feed, dispatch, rememberCommunitySort]); + try { + await dispatch(getFeedSort({ feed, context })); + } catch (error) { + _setSort((_sort) => _sort ?? defaultSort); // fallback if indexeddb unavailable + throw error; + } + })(); + }, [feed, dispatch, rememberCommunitySort, context, defaultSort]); useEffect(() => { if (!rememberCommunitySort) return; if (sort) return; - if (feedSort === undefined) return; + if (feedSort === undefined) return; // null = loaded, but custom community sort not found _setSort(feedSort ?? defaultSort); }, [feedSort, sort, defaultSort, rememberCommunitySort]); - function setSort(sort: SortType) { + function setSort(sort: Sort) { if (rememberCommunitySort && feed) { dispatch( setFeedSort({ feed, sort, - }), + context, + } as SetSortActionPayload), ); } diff --git a/src/features/settings/general/comments/Comments.tsx b/src/features/settings/general/comments/Comments.tsx index 7fe31bc51..97773f742 100644 --- a/src/features/settings/general/comments/Comments.tsx +++ b/src/features/settings/general/comments/Comments.tsx @@ -9,6 +9,7 @@ import TouchFriendlyLinks from "./TouchFriendlyLinks"; import TapToCollapse from "./TapToCollapse"; import ShowCommentImages from "./ShowCommentImages"; import ShowCollapsed from "./ShowCollapsed"; +import RememberCommunityCommentSort from "./RememberCommunityCommentSort"; export default function Comments() { return ( @@ -18,6 +19,7 @@ export default function Comments() { + diff --git a/src/features/settings/general/comments/RememberCommunityCommentSort.tsx b/src/features/settings/general/comments/RememberCommunityCommentSort.tsx new file mode 100644 index 000000000..c1fff43c6 --- /dev/null +++ b/src/features/settings/general/comments/RememberCommunityCommentSort.tsx @@ -0,0 +1,24 @@ +import { IonItem, IonToggle } from "@ionic/react"; + +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { setRememberCommunityCommentSort } from "../../settingsSlice"; + +export default function RememberCommunityCommentSort() { + const dispatch = useAppDispatch(); + const rememberCommunitySort = useAppSelector( + (state) => state.settings.general.comments.rememberCommunitySort, + ); + + return ( + + + dispatch(setRememberCommunityCommentSort(e.detail.checked)) + } + > + Remember Community Sort + + + ); +} diff --git a/src/features/settings/general/posts/Posts.tsx b/src/features/settings/general/posts/Posts.tsx index c65460bef..7d8fffa43 100644 --- a/src/features/settings/general/posts/Posts.tsx +++ b/src/features/settings/general/posts/Posts.tsx @@ -3,7 +3,7 @@ import { ListHeader } from "../../shared/formatting"; import InfiniteScrolling from "./InfiniteScrolling"; import UpvoteOnSave from "./UpvoteOnSave"; import DefaultSort from "./DefaultSort"; -import RememberCommunitySort from "./RememberCommunitySort"; +import RememberCommunityPostSort from "./RememberCommunityPostSort"; import AutoplayMedia from "./AutoplayMedia"; export default function Posts() { @@ -19,7 +19,7 @@ export default function Posts() { - + diff --git a/src/features/settings/general/posts/RememberCommunitySort.tsx b/src/features/settings/general/posts/RememberCommunityPostSort.tsx similarity index 58% rename from src/features/settings/general/posts/RememberCommunitySort.tsx rename to src/features/settings/general/posts/RememberCommunityPostSort.tsx index 814aa8943..5290e45d0 100644 --- a/src/features/settings/general/posts/RememberCommunitySort.tsx +++ b/src/features/settings/general/posts/RememberCommunityPostSort.tsx @@ -1,20 +1,20 @@ import { IonItem, IonToggle } from "@ionic/react"; import { useAppDispatch, useAppSelector } from "../../../../store"; -import { setRememberCommunitySort } from "../../settingsSlice"; +import { setRememberCommunityPostSort } from "../../settingsSlice"; -export default function RememberCommunitySort() { +export default function RememberCommunityPostSort() { const dispatch = useAppDispatch(); - const infiniteScrolling = useAppSelector( + const rememberCommunitySort = useAppSelector( (state) => state.settings.general.posts.rememberCommunitySort, ); return ( - dispatch(setRememberCommunitySort(e.detail.checked)) + dispatch(setRememberCommunityPostSort(e.detail.checked)) } > Remember Community Sort diff --git a/src/features/settings/settingsSlice.tsx b/src/features/settings/settingsSlice.tsx index a6720e480..6ec695729 100644 --- a/src/features/settings/settingsSlice.tsx +++ b/src/features/settings/settingsSlice.tsx @@ -110,6 +110,7 @@ interface SettingsState { touchFriendlyLinks: boolean; showCommentImages: boolean; showCollapsed: boolean; + rememberCommunitySort: boolean; }; posts: { sort: SortType; @@ -206,6 +207,7 @@ export const initialState: SettingsState = { touchFriendlyLinks: true, showCommentImages: true, showCollapsed: false, + rememberCommunitySort: false, }, posts: { sort: "Active", @@ -483,10 +485,15 @@ export const appearanceSlice = createSlice({ db.setSetting("upvote_on_save", action.payload); }, - setRememberCommunitySort(state, action: PayloadAction) { + setRememberCommunityPostSort(state, action: PayloadAction) { state.general.posts.rememberCommunitySort = action.payload; - db.setSetting("remember_community_sort", action.payload); + db.setSetting("remember_community_post_sort", action.payload); + }, + setRememberCommunityCommentSort(state, action: PayloadAction) { + state.general.comments.rememberCommunitySort = action.payload; + + db.setSetting("remember_community_comment_sort", action.payload); }, setAutoplayMedia(state, action: PayloadAction) { state.general.posts.autoplayMedia = action.payload; @@ -673,8 +680,11 @@ export const fetchSettingsFromDatabase = createAsyncThunk( ); const infinite_scrolling = await db.getSetting("infinite_scrolling"); const upvote_on_save = await db.getSetting("upvote_on_save"); - const remember_community_sort = await db.getSetting( - "remember_community_sort", + const remember_community_post_sort = await db.getSetting( + "remember_community_post_sort", + ); + const remember_community_comment_sort = await db.getSetting( + "remember_community_comment_sort", ); const autoplay_media = await db.getSetting("autoplay_media"); const enable_haptic_feedback = await db.getSetting( @@ -787,6 +797,9 @@ export const fetchSettingsFromDatabase = createAsyncThunk( showCollapsed: show_collapsed_comment ?? initialState.general.comments.showCollapsed, + rememberCommunitySort: + remember_community_comment_sort ?? + initialState.general.comments.rememberCommunitySort, }, posts: { disableMarkingRead: @@ -813,7 +826,7 @@ export const fetchSettingsFromDatabase = createAsyncThunk( upvote_on_save ?? initialState.general.posts.upvoteOnSave, sort: default_post_sort ?? initialState.general.posts.sort, rememberCommunitySort: - remember_community_sort ?? + remember_community_post_sort ?? initialState.general.posts.rememberCommunitySort, autoplayMedia: autoplay_media ?? initialState.general.posts.autoplayMedia, @@ -893,7 +906,8 @@ export const { setDisableAutoHideInCommunities, setInfiniteScrolling, setUpvoteOnSave, - setRememberCommunitySort, + setRememberCommunityPostSort, + setRememberCommunityCommentSort, setAutoplayMedia, setTheme, setEnableHapticFeedback, diff --git a/src/routes/pages/posts/PostPage.tsx b/src/routes/pages/posts/PostPage.tsx index 7061841ff..e6c9fb626 100644 --- a/src/routes/pages/posts/PostPage.tsx +++ b/src/routes/pages/posts/PostPage.tsx @@ -14,9 +14,8 @@ import { import { useAppDispatch, useAppSelector } from "../../../store"; import { useParams } from "react-router"; import { styled } from "@linaria/react"; -import React, { memo, useCallback, useEffect, useState } from "react"; +import React, { memo, useCallback, useEffect } from "react"; import { getPost } from "../../../features/post/postSlice"; -import { CommentSortType } from "lemmy-js-client"; import { useBuildGeneralBrowseLink } from "../../../helpers/routes"; import CommentSort from "../../../features/comment/CommentSort"; import MoreActions from "../../../features/post/shared/MoreActions"; @@ -28,6 +27,8 @@ import MoreModActions from "../../../features/post/shared/MoreModAction"; import { useSetActivePage } from "../../../features/auth/AppContext"; import { useRef } from "react"; import AppHeader from "../../../features/shared/AppHeader"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; +import { getRemoteHandleFromHandle } from "../../../helpers/lemmy"; export const CenteredSpinner = styled(IonSpinner)` position: relative; @@ -74,10 +75,16 @@ const PostPageContent = memo(function PostPageContent({ const post = useAppSelector((state) => state.post.postById[id]); const client = useClient(); const dispatch = useAppDispatch(); - const defaultSort = useAppSelector( - (state) => state.settings.general.comments.sort, + + const connectedInstance = useAppSelector( + (state) => state.auth.connectedInstance, ); - const [sort, setSort] = useState(defaultSort); + const [sort, setSort] = useSortByFeed("comments", { + remoteCommunityHandle: getRemoteHandleFromHandle( + community, + connectedInstance, + ), + }); const postDeletedById = useAppSelector((state) => state.post.postDeletedById); const postIfFound = typeof post === "object" ? post : undefined; @@ -135,6 +142,8 @@ const PostPageContent = memo(function PostPageContent({
Post not found
, ); + if (!sort) return; + return ( (); const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort(); + const [sort, setSort] = useSortByFeed("posts"); const search = decodeURIComponent(_encodedSearch); diff --git a/src/routes/pages/search/results/SearchFeedResultsPage.tsx b/src/routes/pages/search/results/SearchFeedResultsPage.tsx index 20806ad4c..c3aa85a67 100644 --- a/src/routes/pages/search/results/SearchFeedResultsPage.tsx +++ b/src/routes/pages/search/results/SearchFeedResultsPage.tsx @@ -20,7 +20,7 @@ import { receivedPosts } from "../../../../features/post/postSlice"; import { receivedComments } from "../../../../features/comment/commentSlice"; import FeedContent from "../../shared/FeedContent"; import { getSortDuration } from "../../../../features/feed/endItems/EndPost"; -import useFeedSort from "../../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../../features/feed/sort/useFeedSort"; import AppHeader from "../../../../features/shared/AppHeader"; interface SearchPostsResultsProps { @@ -37,7 +37,7 @@ export default function SearchFeedResultsPage({ }>(); const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort(); + const [sort, setSort] = useSortByFeed("posts"); const search = decodeURIComponent(_encodedSearch); diff --git a/src/routes/pages/shared/CommunityPage.tsx b/src/routes/pages/shared/CommunityPage.tsx index 55d559bea..24ed3d0ba 100644 --- a/src/routes/pages/shared/CommunityPage.tsx +++ b/src/routes/pages/shared/CommunityPage.tsx @@ -34,7 +34,7 @@ import CommunitySearchResults from "../../../features/community/search/Community import { getSortDuration } from "../../../features/feed/endItems/EndPost"; import ModActions from "../../../features/community/mod/ModActions"; import { useOptimizedIonRouter } from "../../../helpers/useOptimizedIonRouter"; -import useFeedSort from "../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; import { CenteredSpinner } from "../posts/PostPage"; import { getRemoteHandleFromHandle } from "../../../helpers/lemmy"; import { useAppSelector } from "../../../store"; @@ -155,7 +155,7 @@ const CommunityPageContent = memo(function CommunityPageContent({ (state) => state.settings.general.posts.showHiddenInCommunities, ); - const [sort, setSort] = useFeedSort({ + const [sort, setSort] = useSortByFeed("posts", { remoteCommunityHandle: getRemoteHandleFromHandle( community, connectedInstance, diff --git a/src/routes/pages/shared/SpecialFeedPage.tsx b/src/routes/pages/shared/SpecialFeedPage.tsx index 5d3a212b1..bd367de84 100644 --- a/src/routes/pages/shared/SpecialFeedPage.tsx +++ b/src/routes/pages/shared/SpecialFeedPage.tsx @@ -22,7 +22,7 @@ import { followIdsSelector } from "../../../features/auth/siteSlice"; import { getHandle } from "../../../helpers/lemmy"; import { CenteredSpinner } from "../posts/PostPage"; import ModActions from "../../../features/community/mod/ModActions"; -import useFeedSort from "../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; import { PageTypeContext } from "../../../features/feed/PageTypeContext"; import AppHeader from "../../../features/shared/AppHeader"; @@ -34,7 +34,7 @@ export default function SpecialFeedPage({ type }: SpecialFeedProps) { const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort({ listingType: type }); + const [sort, setSort] = useSortByFeed("posts", { listingType: type }); const followIds = useAppSelector(followIdsSelector); const communityByHandle = useAppSelector( diff --git a/src/services/db.ts b/src/services/db.ts index b886ee4cb..6e8950f66 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -306,6 +306,7 @@ export type SettingValueTypes = { favorite_communities: string[]; migration_links: string[]; default_comment_sort: CommentDefaultSort; + default_comment_sort_by_feed: CommentDefaultSort; disable_marking_posts_read: boolean; mark_read_on_scroll: boolean; show_hide_read_button: boolean; @@ -338,7 +339,8 @@ export type SettingValueTypes = { upvote_on_save: boolean; default_post_sort: SortType; default_post_sort_by_feed: SortType; - remember_community_sort: boolean; + remember_community_post_sort: boolean; + remember_community_comment_sort: boolean; embed_crossposts: boolean; show_community_icons: boolean; autoplay_media: AutoplayMediaType; @@ -502,6 +504,13 @@ export class WefwefDB extends Dexie { data `, }); + + this.version(8).upgrade(async () => { + await this.settings + .where("key") + .equals("remember_community_sort") + .modify({ key: "remember_community_post_sort" }); + }); } /*