From 7633d70435950a41438119af9ea105f6ce0ac6e1 Mon Sep 17 00:00:00 2001 From: hxp0618 <1169924772@qq.com> Date: Fri, 10 Jan 2025 16:32:59 +0800 Subject: [PATCH] feat: MinApp added to the sidebar does not support direct hiding. --- .../src/components/Popups/AppStorePopover.tsx | 16 ++- src/renderer/src/i18n/locales/en-us.json | 1 + src/renderer/src/i18n/locales/ja-jp.json | 1 + src/renderer/src/i18n/locales/ru-ru.json | 1 + src/renderer/src/i18n/locales/zh-cn.json | 1 + src/renderer/src/i18n/locales/zh-tw.json | 13 +- src/renderer/src/pages/apps/App.tsx | 7 +- src/renderer/src/pages/apps/AppsPage.tsx | 10 +- .../DisplaySettings/MiniAppIconsManager.tsx | 123 +++++++++++++----- 9 files changed, 125 insertions(+), 48 deletions(-) diff --git a/src/renderer/src/components/Popups/AppStorePopover.tsx b/src/renderer/src/components/Popups/AppStorePopover.tsx index 25e918be..5f071963 100644 --- a/src/renderer/src/components/Popups/AppStorePopover.tsx +++ b/src/renderer/src/components/Popups/AppStorePopover.tsx @@ -1,10 +1,11 @@ import { Center } from '@renderer/components/Layout' import { getAllMinApps } from '@renderer/config/minapps' +import { useSettings } from '@renderer/hooks/useSettings' import App from '@renderer/pages/apps/App' import { Popover } from 'antd' import { Empty } from 'antd' import { isEmpty } from 'lodash' -import { FC, useState } from 'react' +import { FC, useMemo, useState } from 'react' import { useHotkeys } from 'react-hotkeys-hook' import styled from 'styled-components' @@ -16,7 +17,14 @@ interface Props { const AppStorePopover: FC = ({ children }) => { const [open, setOpen] = useState(false) - const apps = getAllMinApps() + const { miniAppIcons } = useSettings() + const allApps = useMemo(() => getAllMinApps(), []) + + // 只显示可见的小程序 + const visibleApps = useMemo(() => { + if (!miniAppIcons?.visible) return allApps + return allApps.filter((app) => miniAppIcons.visible.includes(app.id)) + }, [allApps, miniAppIcons?.visible]) useHotkeys('esc', () => { setOpen(false) @@ -29,10 +37,10 @@ const AppStorePopover: FC = ({ children }) => { const content = ( - {apps.map((app) => ( + {visibleApps.map((app) => ( ))} - {isEmpty(apps) && ( + {isEmpty(visibleApps) && (
diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 07d00629..9e50aa0e 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -411,6 +411,7 @@ "display.minApp.visible": "Visible MinApp", "display.minApp.disabled": "Hidden MinApp", "display.minApp.empty": "Drag minApp from the left to hide them here", + "display.minApp.pinnedError": "MinApp that have been added to the sidebar do not support hiding. If you want to hide them, please remove them from the sidebar first.", "display.topic.title": "Topic Settings", "display.custom.css": "Custom CSS", "display.custom.css.placeholder": "/* Put custom CSS here */", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 67d72602..1770d8d0 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -412,6 +412,7 @@ "display.minApp.visible": "表示中ミニプログラム", "display.minApp.disabled": "非表示ミニプログラム", "display.minApp.empty": "非表示にしたいアプレットを左からここまでドラッグします", + "display.minApp.pinnedError": "サイドバーに追加されたミニ プログラムは非表示をサポートしていません。非表示にしたい場合は、まずサイドバーから削除してください", "input.auto_translate_with_space": "スペースを3回押して翻訳", "messages.divider": "メッセージ間に区切り線を表示", "messages.input.paste_long_text_as_file": "長いテキストをファイルとして貼り付け", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index ba4c767e..54dbb2f8 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -411,6 +411,7 @@ "display.minApp.visible": "Отображаемый апплет", "display.minApp.disabled": "скрытый апплет", "display.minApp.empty": "Перетащите апплет, который хотите скрыть, слева сюда", + "display.minApp.pinnedError": "Мини-программы, добавленные на боковую панель, не поддерживают скрытие. Если вы хотите скрыть их, сначала удалите их с боковой панели", "display.topic.title": "Настройки топиков", "display.custom.css": "Пользовательский CSS", "display.custom.css.placeholder": "/* Здесь введите пользовательский CSS */", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 95fcf109..4a22f9a6 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -412,6 +412,7 @@ "display.minApp.visible": "显示的小程序", "display.minApp.disabled": "隐藏的小程序", "display.minApp.empty": "把要隐藏的小程序从左侧拖拽到这里", + "display.minApp.pinnedError": "已经添加到侧边栏的小程序,不支持隐藏,如需隐藏请先从侧边栏移除", "display.topic.title": "话题设置", "display.custom.css": "自定义 CSS", "display.custom.css.placeholder": "/* 这里写自定义CSS */", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 22c4735a..62a54f15 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -408,17 +408,14 @@ "display.sidebar.empty": "把要隱藏的功能從左側拖拽到這裡", "display.sidebar.visible": "顯示我的側邊欄圖標", "display.sidebar.disabled": "隱藏我的側邊欄圖標", + "display.minApp.title": "小程序顯示設定", + "display.minApp.visible": "顯示的小程序", + "display.minApp.disabled": "隱藏的小程序", + "display.minApp.empty": "把要隱藏的小程序從左側拖拽到這裡", + "display.minApp.pinnedError": "已新增至側邊欄的小程序,不支援隱藏,如需隱藏請先從側邊欄移除", "display.custom.css": "自定義 CSS", "display.custom.css.placeholder": "/* 這裡寫自定義 CSS */", "input.auto_translate_with_space": "快速敲擊3次空格翻譯", - "display": { - "minApp": { - "title": "小程序顯示設定", - "visible": "顯示的小程序", - "disabled": "隱藏的小程序", - "empty": "把要隱藏的小程序從左側拖拽到這裡" - } - }, "messages.divider": "訊息間顯示分隔線", "messages.input.paste_long_text_as_file": "將長文本貼上為檔案", "messages.input.send_shortcuts": "發送快捷鍵", diff --git a/src/renderer/src/pages/apps/App.tsx b/src/renderer/src/pages/apps/App.tsx index 532bb9b6..2d933b59 100644 --- a/src/renderer/src/pages/apps/App.tsx +++ b/src/renderer/src/pages/apps/App.tsx @@ -8,7 +8,6 @@ import { FC } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' - interface Props { app: MinAppType onClick?: () => void @@ -20,6 +19,7 @@ const App: FC = ({ app, onClick, size = 60 }) => { const dispatch = useAppDispatch() const { miniAppIcons } = useAppSelector((state) => state.settings) const isPinned = miniAppIcons?.pinned.includes(app.id) + const isVisible = miniAppIcons?.visible.includes(app.id) const handleClick = () => { MinApp.start(app) @@ -38,13 +38,16 @@ const App: FC = ({ app, onClick, size = 60 }) => { dispatch( setMiniAppIcons({ ...miniAppIcons, - pinned: newPinned + pinned: newPinned, + visible: isPinned ? miniAppIcons.visible : [...new Set([...miniAppIcons.visible, app.id])] }) ) } } ] + if (!isVisible) return null + return ( diff --git a/src/renderer/src/pages/apps/AppsPage.tsx b/src/renderer/src/pages/apps/AppsPage.tsx index 865e452a..0432d287 100644 --- a/src/renderer/src/pages/apps/AppsPage.tsx +++ b/src/renderer/src/pages/apps/AppsPage.tsx @@ -17,11 +17,15 @@ const AppsPage: FC = () => { const { miniAppIcons } = useSettings() const allApps = useMemo(() => getAllMinApps(), []) - // 只显示可见的小程序 + // 只显示可见的小程序,但包括所有固定的小程序 const visibleApps = useMemo(() => { if (!miniAppIcons?.visible) return allApps - return allApps.filter((app) => miniAppIcons.visible.includes(app.id)) - }, [allApps, miniAppIcons?.visible]) + const visibleIds = new Set([ + ...miniAppIcons.visible, + ...(miniAppIcons.pinned || []) // 确保固定的小程序总是可见 + ]) + return allApps.filter((app) => visibleIds.has(app.id)) + }, [allApps, miniAppIcons?.visible, miniAppIcons?.pinned]) const filteredApps = search ? visibleApps.filter( diff --git a/src/renderer/src/pages/settings/DisplaySettings/MiniAppIconsManager.tsx b/src/renderer/src/pages/settings/DisplaySettings/MiniAppIconsManager.tsx index 48e3572c..3d3a68db 100644 --- a/src/renderer/src/pages/settings/DisplaySettings/MiniAppIconsManager.tsx +++ b/src/renderer/src/pages/settings/DisplaySettings/MiniAppIconsManager.tsx @@ -8,13 +8,13 @@ import { DropResult } from '@hello-pangea/dnd' import { getAllMinApps } from '@renderer/config/minapps' +import { useSettings } from '@renderer/hooks/useSettings' import { useAppDispatch } from '@renderer/store' +import { MinAppIcon, setMiniAppIcons } from '@renderer/store/settings' import { FC, useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' -import { MinAppIcon, setMiniAppIcons } from '../../../store/settings' - interface MiniAppManagerProps { visibleMiniApps: MinAppIcon[] disabledMiniApps: MinAppIcon[] @@ -29,6 +29,50 @@ interface AppInfo { logo?: string } +// 添加 reorderLists 函数的接口定义 +interface ReorderListsParams { + sourceList: MinAppIcon[] + destList: MinAppIcon[] + sourceIndex: number + destIndex: number + isSameList: boolean +} + +interface ReorderListsResult { + sourceList: MinAppIcon[] + destList: MinAppIcon[] +} + +// 添加 reorderLists 函数 +const reorderLists = ({ + sourceList, + destList, + sourceIndex, + destIndex, + isSameList +}: ReorderListsParams): ReorderListsResult => { + if (isSameList) { + // 在同一列表内重新排序 + const newList = [...sourceList] + const [removed] = newList.splice(sourceIndex, 1) + newList.splice(destIndex, 0, removed) + return { + sourceList: newList, + destList: destList + } + } else { + // 在不同列表间移动 + const newSourceList = [...sourceList] + const [removed] = newSourceList.splice(sourceIndex, 1) + const newDestList = [...destList] + newDestList.splice(destIndex, 0, removed) + return { + sourceList: newSourceList, + destList: newDestList + } + } +} + const MiniAppIconsManager: FC = ({ visibleMiniApps, disabledMiniApps, @@ -37,6 +81,7 @@ const MiniAppIconsManager: FC = ({ }) => { const { t } = useTranslation() const dispatch = useAppDispatch() + const { miniAppIcons } = useSettings() const allApps = useMemo(() => getAllMinApps(), []) // 创建 app 信息的 Map 缓存 @@ -58,48 +103,64 @@ const MiniAppIconsManager: FC = ({ ) const handleListUpdate = useCallback( - (visible: MinAppIcon[], disabled: MinAppIcon[]) => { - setVisibleMiniApps(visible) - setDisabledMiniApps(disabled) - dispatch(setMiniAppIcons({ visible, disabled, pinned: [] })) + (newVisible: MinAppIcon[], newDisabled: MinAppIcon[]) => { + setVisibleMiniApps(newVisible) + setDisabledMiniApps(newDisabled) + + // 保持 pinned 状态不变 + dispatch( + setMiniAppIcons({ + visible: newVisible, + disabled: newDisabled, + pinned: miniAppIcons.pinned // 保持原有的 pinned 状态 + }) + ) }, - [dispatch, setVisibleMiniApps, setDisabledMiniApps] + [dispatch, setVisibleMiniApps, setDisabledMiniApps, miniAppIcons.pinned] ) const onDragEnd = useCallback( (result: DropResult) => { + if (!result.destination) return + const { source, destination } = result - if (!destination) return + const sourceList = source.droppableId as ListType + const destList = destination.droppableId as ListType - const sourceList = source.droppableId === 'visible' ? visibleMiniApps : disabledMiniApps - const destList = destination.droppableId === 'visible' ? visibleMiniApps : disabledMiniApps + // 如果是 pinned 的小程序,不允许拖到 disabled + if (destList === 'disabled') { + const draggedApp = sourceList === 'visible' ? visibleMiniApps[source.index] : disabledMiniApps[source.index] - if (source.droppableId === destination.droppableId) { - const newList = [...sourceList] - const [removed] = newList.splice(source.index, 1) - newList.splice(destination.index, 0, removed) - - handleListUpdate( - source.droppableId === 'visible' ? newList : visibleMiniApps, - source.droppableId === 'disabled' ? newList : disabledMiniApps - ) - } else { - const sourceNewList = [...sourceList] - const [removed] = sourceNewList.splice(source.index, 1) - const destNewList = [...destList] - destNewList.splice(destination.index, 0, removed) - - handleListUpdate( - destination.droppableId === 'visible' ? destNewList : sourceNewList, - destination.droppableId === 'disabled' ? destNewList : sourceNewList - ) + if (miniAppIcons.pinned.includes(draggedApp)) { + window.message.error(t('settings.display.minApp.pinnedError')) + return + } } + + const newLists = reorderLists({ + sourceList: sourceList === 'visible' ? visibleMiniApps : disabledMiniApps, + destList: destList === 'visible' ? visibleMiniApps : disabledMiniApps, + sourceIndex: source.index, + destIndex: destination.index, + isSameList: sourceList === destList + }) + + handleListUpdate( + sourceList === 'visible' ? newLists.sourceList : newLists.destList, + sourceList === 'visible' ? newLists.destList : newLists.sourceList + ) }, - [visibleMiniApps, disabledMiniApps, handleListUpdate] + [visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t] ) const onMoveMiniApp = useCallback( (program: MinAppIcon, fromList: ListType) => { + // 如果是从可见列表移动到隐藏列表,且程序是 pinned 状态,则阻止移动 + if (fromList === 'visible' && miniAppIcons.pinned.includes(program)) { + window.message.error(t('settings.display.minApp.pinnedError')) + return + } + const isMovingToVisible = fromList === 'disabled' const newVisible = isMovingToVisible ? [...visibleMiniApps, program] @@ -110,7 +171,7 @@ const MiniAppIconsManager: FC = ({ handleListUpdate(newVisible, newDisabled) }, - [visibleMiniApps, disabledMiniApps, handleListUpdate] + [visibleMiniApps, disabledMiniApps, handleListUpdate, miniAppIcons.pinned, t] ) const renderProgramItem = (program: MinAppIcon, provided: DraggableProvided, listType: ListType) => {