diff --git a/packages/shared/IpcChannel.ts b/packages/shared/IpcChannel.ts index 32903df6e5..bf1d2236e1 100644 --- a/packages/shared/IpcChannel.ts +++ b/packages/shared/IpcChannel.ts @@ -189,6 +189,7 @@ export enum IpcChannel { Selection_SetFilterMode = 'selection:set-filter-mode', Selection_SetFilterList = 'selection:set-filter-list', Selection_SetFollowToolbar = 'selection:set-follow-toolbar', + Selection_SetRemeberWinSize = 'selection:set-remeber-win-size', Selection_ActionWindowClose = 'selection:action-window-close', Selection_ActionWindowMinimize = 'selection:action-window-minimize', Selection_ActionWindowPin = 'selection:action-window-pin', diff --git a/src/main/services/ConfigManager.ts b/src/main/services/ConfigManager.ts index a51f1a076b..5327aebbf7 100644 --- a/src/main/services/ConfigManager.ts +++ b/src/main/services/ConfigManager.ts @@ -20,6 +20,7 @@ export enum ConfigKeys { SelectionAssistantEnabled = 'selectionAssistantEnabled', SelectionAssistantTriggerMode = 'selectionAssistantTriggerMode', SelectionAssistantFollowToolbar = 'selectionAssistantFollowToolbar', + SelectionAssistantRemeberWinSize = 'selectionAssistantRemeberWinSize', SelectionAssistantFilterMode = 'selectionAssistantFilterMode', SelectionAssistantFilterList = 'selectionAssistantFilterList' } @@ -175,6 +176,14 @@ export class ConfigManager { this.setAndNotify(ConfigKeys.SelectionAssistantFollowToolbar, value) } + getSelectionAssistantRemeberWinSize(): boolean { + return this.get(ConfigKeys.SelectionAssistantRemeberWinSize, false) + } + + setSelectionAssistantRemeberWinSize(value: boolean) { + this.setAndNotify(ConfigKeys.SelectionAssistantRemeberWinSize, value) + } + getSelectionAssistantFilterMode(): string { return this.get(ConfigKeys.SelectionAssistantFilterMode, 'default') } diff --git a/src/main/services/SelectionService.ts b/src/main/services/SelectionService.ts index ebe17b3e0e..a191e67799 100644 --- a/src/main/services/SelectionService.ts +++ b/src/main/services/SelectionService.ts @@ -60,6 +60,7 @@ export class SelectionService { private triggerMode = 'selected' private isFollowToolbar = true + private isRemeberWinSize = false private filterMode = 'default' private filterList: string[] = [] @@ -86,6 +87,11 @@ export class SelectionService { private readonly ACTION_WINDOW_WIDTH = 500 private readonly ACTION_WINDOW_HEIGHT = 400 + private lastActionWindowSize: { width: number; height: number } = { + width: this.ACTION_WINDOW_WIDTH, + height: this.ACTION_WINDOW_HEIGHT + } + private constructor() { try { if (!SelectionHook) { @@ -140,6 +146,7 @@ export class SelectionService { private initConfig() { this.triggerMode = configManager.getSelectionAssistantTriggerMode() this.isFollowToolbar = configManager.getSelectionAssistantFollowToolbar() + this.isRemeberWinSize = configManager.getSelectionAssistantRemeberWinSize() this.filterMode = configManager.getSelectionAssistantFilterMode() this.filterList = configManager.getSelectionAssistantFilterList() @@ -154,6 +161,17 @@ export class SelectionService { this.isFollowToolbar = isFollowToolbar }) + configManager.subscribe(ConfigKeys.SelectionAssistantRemeberWinSize, (isRemeberWinSize: boolean) => { + this.isRemeberWinSize = isRemeberWinSize + //when off, reset the last action window size to default + if (!this.isRemeberWinSize) { + this.lastActionWindowSize = { + width: this.ACTION_WINDOW_WIDTH, + height: this.ACTION_WINDOW_HEIGHT + } + } + }) + configManager.subscribe(ConfigKeys.SelectionAssistantFilterMode, (filterMode: string) => { this.filterMode = filterMode this.setHookGlobalFilterMode(this.filterMode, this.filterList) @@ -810,8 +828,8 @@ export class SelectionService { */ private createPreloadedActionWindow(): BrowserWindow { const preloadedActionWindow = new BrowserWindow({ - width: this.ACTION_WINDOW_WIDTH, - height: this.ACTION_WINDOW_HEIGHT, + width: this.isRemeberWinSize ? this.lastActionWindowSize.width : this.ACTION_WINDOW_WIDTH, + height: this.isRemeberWinSize ? this.lastActionWindowSize.height : this.ACTION_WINDOW_HEIGHT, minWidth: 300, minHeight: 200, frame: false, @@ -885,6 +903,16 @@ export class SelectionService { } }) + //remember the action window size + actionWindow.on('resized', () => { + if (this.isRemeberWinSize) { + this.lastActionWindowSize = { + width: actionWindow.getBounds().width, + height: actionWindow.getBounds().height + } + } + }) + this.actionWindows.add(actionWindow) // Asynchronously create a new preloaded window @@ -907,30 +935,58 @@ export class SelectionService { * @param actionWindow Window to position and show */ private showActionWindow(actionWindow: BrowserWindow) { + let actionWindowWidth = this.ACTION_WINDOW_WIDTH + let actionWindowHeight = this.ACTION_WINDOW_HEIGHT + + //if remember win size is true, use the last remembered size + if (this.isRemeberWinSize) { + actionWindowWidth = this.lastActionWindowSize.width + actionWindowHeight = this.lastActionWindowSize.height + } + + //center way if (!this.isFollowToolbar || !this.toolbarWindow) { + if (this.isRemeberWinSize) { + actionWindow.setBounds({ + width: actionWindowWidth, + height: actionWindowHeight + }) + } + actionWindow.show() this.hideToolbar() return } + //follow toolbar + const toolbarBounds = this.toolbarWindow!.getBounds() const display = screen.getDisplayNearestPoint({ x: toolbarBounds.x, y: toolbarBounds.y }) const workArea = display.workArea const GAP = 6 // 6px gap from screen edges + //make sure action window is inside screen + if (actionWindowWidth > workArea.width - 2 * GAP) { + actionWindowWidth = workArea.width - 2 * GAP + } + + if (actionWindowHeight > workArea.height - 2 * GAP) { + actionWindowHeight = workArea.height - 2 * GAP + } + // Calculate initial position to center action window horizontally below toolbar - let posX = Math.round(toolbarBounds.x + (toolbarBounds.width - this.ACTION_WINDOW_WIDTH) / 2) + let posX = Math.round(toolbarBounds.x + (toolbarBounds.width - actionWindowWidth) / 2) let posY = Math.round(toolbarBounds.y) // Ensure action window stays within screen boundaries with a small gap - if (posX + this.ACTION_WINDOW_WIDTH > workArea.x + workArea.width) { - posX = workArea.x + workArea.width - this.ACTION_WINDOW_WIDTH - GAP + if (posX + actionWindowWidth > workArea.x + workArea.width) { + posX = workArea.x + workArea.width - actionWindowWidth - GAP } else if (posX < workArea.x) { posX = workArea.x + GAP } - if (posY + this.ACTION_WINDOW_HEIGHT > workArea.y + workArea.height) { + if (posY + actionWindowHeight > workArea.y + workArea.height) { // If window would go below screen, try to position it above toolbar - posY = workArea.y + workArea.height - this.ACTION_WINDOW_HEIGHT - GAP + posY = workArea.y + workArea.height - actionWindowHeight - GAP } else if (posY < workArea.y) { posY = workArea.y + GAP } @@ -938,8 +994,8 @@ export class SelectionService { actionWindow.setPosition(posX, posY, false) //KEY to make window not resize actionWindow.setBounds({ - width: this.ACTION_WINDOW_WIDTH, - height: this.ACTION_WINDOW_HEIGHT, + width: actionWindowWidth, + height: actionWindowHeight, x: posX, y: posY }) @@ -1021,6 +1077,10 @@ export class SelectionService { configManager.setSelectionAssistantFollowToolbar(isFollowToolbar) }) + ipcMain.handle(IpcChannel.Selection_SetRemeberWinSize, (_, isRemeberWinSize: boolean) => { + configManager.setSelectionAssistantRemeberWinSize(isRemeberWinSize) + }) + ipcMain.handle(IpcChannel.Selection_SetFilterMode, (_, filterMode: string) => { configManager.setSelectionAssistantFilterMode(filterMode) }) diff --git a/src/preload/index.ts b/src/preload/index.ts index 625fbfbfde..25b8bf8c7a 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -218,6 +218,8 @@ const api = { setTriggerMode: (triggerMode: string) => ipcRenderer.invoke(IpcChannel.Selection_SetTriggerMode, triggerMode), setFollowToolbar: (isFollowToolbar: boolean) => ipcRenderer.invoke(IpcChannel.Selection_SetFollowToolbar, isFollowToolbar), + setRemeberWinSize: (isRemeberWinSize: boolean) => + ipcRenderer.invoke(IpcChannel.Selection_SetRemeberWinSize, isRemeberWinSize), setFilterMode: (filterMode: string) => ipcRenderer.invoke(IpcChannel.Selection_SetFilterMode, filterMode), setFilterList: (filterList: string[]) => ipcRenderer.invoke(IpcChannel.Selection_SetFilterList, filterList), processAction: (actionItem: ActionItem) => ipcRenderer.invoke(IpcChannel.Selection_ProcessAction, actionItem), diff --git a/src/renderer/src/hooks/useSelectionAssistant.ts b/src/renderer/src/hooks/useSelectionAssistant.ts index 17bd14e977..93a51b2c70 100644 --- a/src/renderer/src/hooks/useSelectionAssistant.ts +++ b/src/renderer/src/hooks/useSelectionAssistant.ts @@ -8,6 +8,7 @@ import { setIsAutoPin, setIsCompact, setIsFollowToolbar, + setIsRemeberWinSize, setSelectionEnabled, setTriggerMode } from '@renderer/store/selectionStore' @@ -40,6 +41,10 @@ export function useSelectionAssistant() { dispatch(setIsFollowToolbar(isFollowToolbar)) window.api.selection.setFollowToolbar(isFollowToolbar) }, + setIsRemeberWinSize: (isRemeberWinSize: boolean) => { + dispatch(setIsRemeberWinSize(isRemeberWinSize)) + window.api.selection.setRemeberWinSize(isRemeberWinSize) + }, setFilterMode: (mode: FilterMode) => { dispatch(setFilterMode(mode)) window.api.selection.setFilterMode(mode) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index c7e72d5a10..1c18afc63a 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1880,6 +1880,10 @@ "title": "Follow Toolbar", "description": "Window position will follow the toolbar. When disabled, it will always be centered." }, + "remember_size": { + "title": "Remember Size", + "description": "Window will display at the last adjusted size during the application running" + }, "auto_close": { "title": "Auto Close", "description": "Automatically close the window when it's not pinned and loses focus" diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index f4b213aa71..aece8cd3d7 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1880,6 +1880,10 @@ "title": "ツールバーに追従", "description": "ウィンドウ位置をツールバーに連動(無効時は中央表示)" }, + "remember_size": { + "title": "サイズを記憶", + "description": "アプリケーション実行中、ウィンドウは最後に調整されたサイズで表示されます" + }, "auto_close": { "title": "自動閉じる", "description": "最前面固定されていない場合、フォーカス喪失時に自動閉じる" diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 29b2be684c..13c1fbb3ac 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1880,6 +1880,10 @@ "title": "Следовать за панелью", "description": "Окно будет следовать за панелью. Иначе - по центру." }, + "remember_size": { + "title": "Запомнить размер", + "description": "При отключенном режиме, окно будет восстанавливаться до последнего размера при запуске приложения" + }, "auto_close": { "title": "Автозакрытие", "description": "Закрывать окно при потере фокуса (если не закреплено)" diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 538ea8e8aa..9519427dae 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1880,6 +1880,10 @@ "title": "跟随工具栏", "description": "窗口位置将跟随工具栏显示,禁用后则始终居中显示" }, + "remember_size": { + "title": "记住大小", + "description": "应用运行期间,窗口会按上次调整的大小显示" + }, "auto_close": { "title": "自动关闭", "description": "当窗口未置顶且失去焦点时,将自动关闭该窗口" diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 3540b8192b..d703265a2c 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1880,6 +1880,10 @@ "title": "跟隨工具列", "description": "視窗位置將跟隨工具列顯示,停用後則始終置中顯示" }, + "remember_size": { + "title": "記住大小", + "description": "應用運行期間,視窗會按上次調整的大小顯示" + }, "auto_close": { "title": "自動關閉", "description": "當視窗未置頂且失去焦點時,將自動關閉該視窗" diff --git a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx index 47bd71b8ea..84ed4ad8fa 100644 --- a/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx +++ b/src/renderer/src/pages/settings/SelectionAssistantSettings/SelectionAssistantSettings.tsx @@ -31,6 +31,7 @@ const SelectionAssistantSettings: FC = () => { isAutoClose, isAutoPin, isFollowToolbar, + isRemeberWinSize, actionItems, actionWindowOpacity, filterMode, @@ -41,6 +42,7 @@ const SelectionAssistantSettings: FC = () => { setIsAutoClose, setIsAutoPin, setIsFollowToolbar, + setIsRemeberWinSize, setActionWindowOpacity, setActionItems, setFilterMode, @@ -140,6 +142,16 @@ const SelectionAssistantSettings: FC = () => { + + + {t('selection.settings.window.remember_size.title')} + {t('selection.settings.window.remember_size.description')} + + setIsRemeberWinSize(checked)} /> + + + + {t('selection.settings.window.auto_close.title')} @@ -191,7 +203,7 @@ const SelectionAssistantSettings: FC = () => { {t('selection.settings.advanced.filter_mode.description')} setFilterMode(e.target.value as FilterMode)} buttonStyle="solid"> {t('selection.settings.advanced.filter_mode.default')} @@ -200,7 +212,7 @@ const SelectionAssistantSettings: FC = () => { - {filterMode !== 'default' && ( + {filterMode && filterMode !== 'default' && ( <> diff --git a/src/renderer/src/store/selectionStore.ts b/src/renderer/src/store/selectionStore.ts index a4269db2bf..09e6c83262 100644 --- a/src/renderer/src/store/selectionStore.ts +++ b/src/renderer/src/store/selectionStore.ts @@ -24,6 +24,7 @@ export const initialState: SelectionState = { isAutoClose: false, isAutoPin: false, isFollowToolbar: true, + isRemeberWinSize: false, filterMode: 'default', filterList: [], actionWindowOpacity: 100, @@ -52,6 +53,9 @@ const selectionSlice = createSlice({ setIsFollowToolbar: (state, action: PayloadAction) => { state.isFollowToolbar = action.payload }, + setIsRemeberWinSize: (state, action: PayloadAction) => { + state.isRemeberWinSize = action.payload + }, setFilterMode: (state, action: PayloadAction) => { state.filterMode = action.payload }, @@ -74,6 +78,7 @@ export const { setIsAutoClose, setIsAutoPin, setIsFollowToolbar, + setIsRemeberWinSize, setFilterMode, setFilterList, setActionWindowOpacity, diff --git a/src/renderer/src/types/selectionTypes.d.ts b/src/renderer/src/types/selectionTypes.d.ts index 3efe539b64..075dde9982 100644 --- a/src/renderer/src/types/selectionTypes.d.ts +++ b/src/renderer/src/types/selectionTypes.d.ts @@ -19,6 +19,7 @@ export interface SelectionState { isAutoClose: boolean isAutoPin: boolean isFollowToolbar: boolean + isRemeberWinSize: boolean filterMode: FilterMode filterList: string[] actionWindowOpacity: number diff --git a/src/renderer/src/windows/selection/action/SelectionActionApp.tsx b/src/renderer/src/windows/selection/action/SelectionActionApp.tsx index b29d16c194..086d46a68e 100644 --- a/src/renderer/src/windows/selection/action/SelectionActionApp.tsx +++ b/src/renderer/src/windows/selection/action/SelectionActionApp.tsx @@ -221,10 +221,12 @@ const SelectionActionApp: FC = () => { } onClick={handleClose} className="close" /> - - {action.id == 'translate' && } - {action.id != 'translate' && } - + + + {action.id == 'translate' && } + {action.id != 'translate' && } + + ) } @@ -340,6 +342,14 @@ const WinButton = styled(Button)` } ` +const MainContainer = styled.div` + display: flex; + justify-content: center; + width: 100%; + height: 100%; + overflow: auto; +` + const Content = styled.div` display: flex; flex-direction: column; @@ -349,7 +359,8 @@ const Content = styled.div` font-size: 14px; -webkit-app-region: none; user-select: text; - width: 100%; + /* width: 100%; */ + max-width: 1280px; ` const OpacitySlider = styled.div` diff --git a/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx b/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx index a481b55eb8..58aa0a60c9 100644 --- a/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx +++ b/src/renderer/src/windows/selection/action/components/ActionGeneral.tsx @@ -266,13 +266,11 @@ const Container = styled.div` const Result = styled.div` margin-top: 4px; width: 100%; - max-width: 960px; ` const MenuContainer = styled.div` display: flex; width: 100%; - max-width: 960px; flex-direction: row; align-items: center; justify-content: flex-end; @@ -309,7 +307,6 @@ const OriginalContent = styled.div` white-space: pre-wrap; word-break: break-word; width: 100%; - max-width: 960px; ` const OriginalContentCopyWrapper = styled.div` diff --git a/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx b/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx index e826495dd8..d115872f77 100644 --- a/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx +++ b/src/renderer/src/windows/selection/action/components/ActionTranslate.tsx @@ -155,7 +155,6 @@ const Result = styled.div` white-space: pre-wrap; word-break: break-word; width: 100%; - max-width: 960px; ` const MenuContainer = styled.div` @@ -164,7 +163,6 @@ const MenuContainer = styled.div` flex-direction: row; align-items: center; justify-content: space-between; - max-width: 960px; ` const OriginalHeader = styled.div` @@ -198,7 +196,6 @@ const OriginalContent = styled.div` white-space: pre-wrap; word-break: break-word; width: 100%; - max-width: 960px; ` const OriginalContentCopyWrapper = styled.div`