feat: only show has media entry item in picture view

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-09-14 13:50:25 +08:00
parent 945dddae25
commit f7dedf2b27
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
8 changed files with 62 additions and 11 deletions

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="#fff" fill-opacity=".01" d="M24 0v24H0V0z"/><path fill="#10161F" d="M17 11a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0"/><path stroke="#10161F" stroke-linecap="round" stroke-width="2" d="m15.857 16.655.354-.354c.666-.666 1-1 1.414-1 .414 0 .747.334 1.414 1L21 18.262m-15 0 4.318-4.318c.667-.667 1-1 1.414-1 .414 0 .748.333 1.414 1l3.473 3.473M18 3.5h-7.5c-3.771 0-5.657 0-6.828 1.172C2.5 5.843 2.5 7.729 2.5 11.5v5.155M17 11a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0Zm-5.5 9.833h4c2.828 0 4.243 0 5.121-.878.879-.879.879-2.293.879-5.122V12.5c0-2.828 0-4.243-.879-5.121C19.743 6.5 18.328 6.5 15.5 6.5h-4c-2.828 0-4.243 0-5.121.879C5.5 8.257 5.5 9.672 5.5 12.5v2.333c0 2.829 0 4.243.879 5.122.878.878 2.293.878 5.121.878Z"/></svg>

After

Width:  |  Height:  |  Size: 789 B

View File

@ -48,11 +48,13 @@
"entry_content.web_app_notice": "Maybe web app doesn't support this content type. But you can download the desktop app.",
"entry_list.zero_unread": "Zero Unread",
"entry_list_header.daily_report": "Daily Report",
"entry_list_header.hide_no_image_items": "Hide no images's entry items",
"entry_list_header.items": "items",
"entry_list_header.new_entries_available": "New entries available",
"entry_list_header.refetch": "Refetch",
"entry_list_header.refresh": "Refresh",
"entry_list_header.show_all": "Show all",
"entry_list_header.show_all_items": "Show all entry items",
"entry_list_header.show_unread_only": "Show unread Only",
"entry_list_header.switch_to_grid": "Switch to Grid",
"entry_list_header.switch_to_masonry": "Switch to Masonry",
@ -109,6 +111,13 @@
"mark_all_read_button.mark_all_as_read": "Mark all as read",
"mark_all_read_button.mark_as_read": "Mark {{which}} as read",
"mark_all_read_button.undo": "Undo",
"player.back_10s": "Back 10s",
"player.close": "Close",
"player.download": "Download",
"player.forward_10s": "Forward 10s",
"player.open_entry": "Open Entry",
"player.playback_rate": "Playback Rate",
"player.volume": "Volume",
"search.empty.no_results": "No results found.",
"search.group.entries": "Entries",
"search.group.feeds": "Feeds",

View File

@ -38,7 +38,7 @@
"entry_list_header.daily_report": "每日报告",
"entry_list_header.items": "内容",
"entry_list_header.new_entries_available": "有新内容",
"entry_list_header.refetch": "重新获取",
"entry_list_header.refetch": "刷新",
"entry_list_header.refresh": "刷新",
"entry_list_header.show_all": "显示全部",
"entry_list_header.show_unread_only": "仅显示未读",

View File

@ -30,6 +30,7 @@ export const createDefaultSettings = (): UISettings => ({
// View
pictureViewMasonry: true,
pictureViewFilterNoImage: false,
// TTS
voice: "en-US-AndrewMultilingualNeural",

View File

@ -15,10 +15,10 @@ import { useTitle, useTypeScriptHappyCallback } from "@renderer/hooks/common"
import { FeedViewType } from "@renderer/lib/enum"
import { cn, isBizId } from "@renderer/lib/utils"
import { useFeed } from "@renderer/queries/feed"
import { entryActions, useEntry } from "@renderer/store/entry"
import { entryActions, getEntry, useEntry } from "@renderer/store/entry"
import { useFeedByIdSelector } from "@renderer/store/feed"
import { useSubscriptionByFeedId } from "@renderer/store/subscription"
import { memo, useCallback, useEffect, useRef, useState } from "react"
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import type {
ScrollSeekConfiguration,
@ -238,17 +238,34 @@ const ListGird = ({
const masonry = useUISettingKey("pictureViewMasonry")
const view = useRouteParamsSelector((s) => s.view)
const feedId = useRouteParamsSelector((s) => s.feedId)
const filterNoImage = useUISettingKey("pictureViewFilterNoImage")
const nextData = useMemo(() => {
if (filterNoImage) {
return virtuosoOptions.data.filter((entryId) => {
const entry = getEntry(entryId)
return entry?.entries.media?.length && entry.entries.media.length > 0
})
}
return virtuosoOptions.data
}, [virtuosoOptions.data, filterNoImage])
if (masonry && view === FeedViewType.Pictures) {
return (
<PictureMasonry
key={feedId}
hasNextPage={virtuosoOptions.totalCount! > virtuosoOptions.data.length}
endReached={virtuosoOptions.endReached}
data={virtuosoOptions.data}
data={nextData}
/>
)
}
return <VirtuosoGrid listClassName={girdClassNames} {...virtuosoOptions} ref={virtuosoRef} />
return (
<VirtuosoGrid
listClassName={girdClassNames}
{...virtuosoOptions}
data={nextData}
ref={virtuosoRef}
/>
)
}
const AddFeedHelper = () => {

View File

@ -96,6 +96,7 @@ export const EntryListHeader: FC<{
<AppendTaildingDivider>
{view === FeedViewType.SocialMedia && <DailyReportButton />}
{view === FeedViewType.Pictures && <SwitchToMasonryButton />}
{view === FeedViewType.Pictures && <FilterNoImageButton />}
</AppendTaildingDivider>
{isOnline ? (
@ -173,6 +174,25 @@ const DailyReportButton: FC = () => {
)
}
const FilterNoImageButton = () => {
const enabled = useUISettingKey("pictureViewFilterNoImage")
const { t } = useTranslation()
return (
<ActionButton
active={enabled}
onClick={() => {
setUISetting("pictureViewFilterNoImage", !enabled)
}}
tooltip={t(
enabled ? "entry_list_header.show_all_items" : "entry_list_header.hide_no_image_items",
)}
>
<i className="i-mgc-photo-album-cute-re" />
</ActionButton>
)
}
const SwitchToMasonryButton = () => {
const isMasonry = useUISettingKey("pictureViewMasonry")
const { t } = useTranslation()
@ -193,7 +213,7 @@ const SwitchToMasonryButton = () => {
})
}}
tooltip={
isMasonry
!isMasonry
? t("entry_list_header.switch_to_masonry")
: t("entry_list_header.switch_to_grid")
}

View File

@ -21,6 +21,7 @@ import { AnimatePresence, m } from "framer-motion"
import { useEffect, useState } from "react"
import Marquee from "react-fast-marquee"
import { useHotkeys } from "react-hotkeys-hook"
import { useTranslation } from "react-i18next"
const handleClickPlay = () => {
AudioPlayer.togglePlayAndPause()
@ -85,6 +86,7 @@ const usePlayerTracker = () => {
}, [show])
}
const CornerPlayerImpl = () => {
const { t } = useTranslation()
const entryId = useAudioPlayerAtomSelector((v) => v.entryId)
const status = useAudioPlayerAtomSelector((v) => v.status)
const isMute = useAudioPlayerAtomSelector((v) => v.isMute)
@ -156,7 +158,7 @@ const CornerPlayerImpl = () => {
<ActionIcon
className="i-mgc-close-cute-re"
onClick={() => AudioPlayer.close()}
label="Close"
label={t("player.close")}
/>
<ActionIcon
className="i-mgc-external-link-cute-re"
@ -167,12 +169,12 @@ const CornerPlayerImpl = () => {
view: FeedViewType.Audios,
})
}
label="Open Entry"
label={t("player.open_entry")}
/>
</div>
<div className="flex items-center">
<ActionIcon
label="Download"
label={t("player.download")}
onClick={() => {
window.open(AudioPlayer.get().src, "_blank")
}}
@ -193,12 +195,12 @@ const CornerPlayerImpl = () => {
<ActionIcon
className="i-mgc-back-2-cute-re"
onClick={() => AudioPlayer.back(10)}
label="Back 10s"
label={t("player.back_10s")}
/>
<ActionIcon
className="i-mgc-forward-2-cute-re"
onClick={() => AudioPlayer.forward(10)}
label="Forward 10s"
label={t("player.forward_10s")}
tooltipAlign="end"
/>
</div>

View File

@ -30,6 +30,7 @@ export interface UISettings {
// view
pictureViewMasonry: boolean
pictureViewFilterNoImage: boolean
// tts
voice: string