change search engine

This commit is contained in:
刘浩远 2020-07-21 12:12:12 +08:00
parent cfed0ac06d
commit 58baa8d935
10 changed files with 102 additions and 17 deletions

View File

@ -1,4 +1,4 @@
import { SourceGroup, ViewType, ThemeSettings, SchemaTypes } from "../schema-types" import { SourceGroup, ViewType, ThemeSettings, SearchEngines } from "../schema-types"
import { ipcRenderer } from "electron" import { ipcRenderer } from "electron"
const settingsBridge = { const settingsBridge = {
@ -75,6 +75,13 @@ const settingsBridge = {
ipcRenderer.invoke("set-fetch-interval", interval) ipcRenderer.invoke("set-fetch-interval", interval)
}, },
getSearchEngine: (): SearchEngines => {
return ipcRenderer.sendSync("get-search-engine")
},
setSearchEngine: (engine: SearchEngines) => {
ipcRenderer.invoke("set-search-engine", engine)
},
getAll: () => { getAll: () => {
return ipcRenderer.sendSync("get-all-settings") as Object return ipcRenderer.sendSync("get-all-settings") as Object
}, },

View File

@ -1,7 +1,7 @@
import * as React from "react" import * as React from "react"
import intl from "react-intl-universal" import intl from "react-intl-universal"
import QRCode from "qrcode.react" import QRCode from "qrcode.react"
import { cutText, googleSearch } from "../scripts/utils" import { cutText, webSearch, getSearchEngineName } from "../scripts/utils"
import { ContextualMenu, IContextualMenuItem, ContextualMenuItemType, DirectionalHint } from "office-ui-fabric-react/lib/ContextualMenu" import { ContextualMenu, IContextualMenuItem, ContextualMenuItemType, DirectionalHint } from "office-ui-fabric-react/lib/ContextualMenu"
import { ContextMenuType } from "../scripts/models/app" import { ContextMenuType } from "../scripts/models/app"
import { RSSItem } from "../scripts/models/item" import { RSSItem } from "../scripts/models/item"
@ -45,6 +45,19 @@ const renderShareQR = (item: IContextualMenuItem) => (
</div> </div>
) )
function getSearchItem(text: string): IContextualMenuItem {
const engine = window.settings.getSearchEngine()
return {
key: "searchText",
text: intl.get("context.search", {
text: cutText(text, 15),
engine: getSearchEngineName(engine)
}),
iconProps: { iconName: "Search" },
onClick: () => webSearch(text, engine)
}
}
export class ContextMenu extends React.Component<ContextMenuProps> { export class ContextMenu extends React.Component<ContextMenuProps> {
getItems = (): IContextualMenuItem[] => { getItems = (): IContextualMenuItem[] => {
switch (this.props.type) { switch (this.props.type) {
@ -137,12 +150,7 @@ export class ContextMenu extends React.Component<ContextMenuProps> {
iconProps: { iconName: "Copy" }, iconProps: { iconName: "Copy" },
onClick: () => { window.utils.writeClipboard(this.props.text) } onClick: () => { window.utils.writeClipboard(this.props.text) }
}, },
{ getSearchItem(this.props.text)
key: "searchText",
text: intl.get("context.search", { text: cutText(this.props.text, 15) }),
iconProps: { iconName: "Search" },
onClick: () => { googleSearch(this.props.text) }
}
] ]
case ContextMenuType.View: return [ case ContextMenuType.View: return [
{ {

View File

@ -1,7 +1,7 @@
import * as React from "react" import * as React from "react"
import intl from "react-intl-universal" import intl from "react-intl-universal"
import { urlTest, byteToMB, calculateItemSize } from "../../scripts/utils" import { urlTest, byteToMB, calculateItemSize, getSearchEngineName } from "../../scripts/utils"
import { ThemeSettings } from "../../schema-types" import { ThemeSettings, SearchEngines } from "../../schema-types"
import { getThemeSettings, setThemeSettings, exportAll } from "../../scripts/settings" import { getThemeSettings, setThemeSettings, exportAll } from "../../scripts/settings"
import { Stack, Label, Toggle, TextField, DefaultButton, ChoiceGroup, IChoiceGroupOption, loadTheme, Dropdown, IDropdownOption, PrimaryButton } from "@fluentui/react" import { Stack, Label, Toggle, TextField, DefaultButton, ChoiceGroup, IChoiceGroupOption, loadTheme, Dropdown, IDropdownOption, PrimaryButton } from "@fluentui/react"
import DangerButton from "../utils/danger-button" import DangerButton from "../utils/danger-button"
@ -73,6 +73,16 @@ class AppTab extends React.Component<AppTabProps, AppTabState> {
this.props.setFetchInterval(item.key as number) this.props.setFetchInterval(item.key as number)
} }
searchEngineOptions = (): IDropdownOption[] => [
SearchEngines.Google, SearchEngines.Bing, SearchEngines.Baidu, SearchEngines.DuckDuckGo
].map(engine => ({
key: engine,
text: getSearchEngineName(engine)
}))
onSearchEngineChanged = (item: IDropdownOption) => {
window.settings.setSearchEngine(item.key as number)
}
deleteOptions = (): IDropdownOption[] => [ deleteOptions = (): IDropdownOption[] => [
{ key: "7", text: intl.get("app.daysAgo", { days: 7 }) }, { key: "7", text: intl.get("app.daysAgo", { days: 7 }) },
{ key: "14", text: intl.get("app.daysAgo", { days: 14 }) }, { key: "14", text: intl.get("app.daysAgo", { days: 14 }) },
@ -153,6 +163,17 @@ class AppTab extends React.Component<AppTabProps, AppTabState> {
</Stack.Item> </Stack.Item>
</Stack> </Stack>
<Label>{intl.get("searchEngine.name")}</Label>
<Stack horizontal>
<Stack.Item>
<Dropdown
defaultSelectedKey={window.settings.getSearchEngine()}
options={this.searchEngineOptions()}
onChanged={this.onSearchEngineChanged}
style={{width: 200}} />
</Stack.Item>
</Stack>
<Stack horizontal verticalAlign="baseline"> <Stack horizontal verticalAlign="baseline">
<Stack.Item grow> <Stack.Item grow>
<Label>{intl.get("app.enableProxy")}</Label> <Label>{intl.get("app.enableProxy")}</Label>

View File

@ -1,6 +1,6 @@
import Store = require("electron-store") import Store = require("electron-store")
import { SchemaTypes, SourceGroup, ViewType, ThemeSettings } from "../schema-types" import { SchemaTypes, SourceGroup, ViewType, ThemeSettings, SearchEngines } from "../schema-types"
import { ipcMain, session, nativeTheme, BrowserWindow, app } from "electron" import { ipcMain, session, nativeTheme, app } from "electron"
import { WindowManager } from "./window" import { WindowManager } from "./window"
export const store = new Store<SchemaTypes>() export const store = new Store<SchemaTypes>()
@ -128,3 +128,11 @@ ipcMain.on("get-fetch-interval", (event) => {
ipcMain.handle("set-fetch-interval", (_, interval: number) => { ipcMain.handle("set-fetch-interval", (_, interval: number) => {
store.set(FETCH_INTEVAL_STORE_KEY, interval) store.set(FETCH_INTEVAL_STORE_KEY, interval)
}) })
const SEARCH_ENGINE_STORE_KEY = "searchEngine"
ipcMain.on("get-search-engine", (event) => {
event.returnValue = store.get(SEARCH_ENGINE_STORE_KEY, SearchEngines.Google)
})
ipcMain.handle("set-search-engine", (_, engine: SearchEngines) => {
store.set(SEARCH_ENGINE_STORE_KEY, engine)
})

View File

@ -28,6 +28,10 @@ export const enum ThemeSettings {
Dark = "dark" Dark = "dark"
} }
export const enum SearchEngines {
Google, Bing, Baidu, DuckDuckGo
}
export type SchemaTypes = { export type SchemaTypes = {
version: string version: string
theme: ThemeSettings theme: ThemeSettings
@ -39,4 +43,5 @@ export type SchemaTypes = {
fontSize: number fontSize: number
menuOn: boolean menuOn: boolean
fetchInterval: number fetchInterval: number
searchEngine: SearchEngines
} }

View File

@ -72,7 +72,7 @@
"copyTitle": "Copy title", "copyTitle": "Copy title",
"copyURL": "Copy link", "copyURL": "Copy link",
"copy": "Copy", "copy": "Copy",
"search": "Search \"{text}\" on Google", "search": "Search \"{text}\" on {engine}",
"view": "View", "view": "View",
"cardView": "Card view", "cardView": "Card view",
"listView": "List view", "listView": "List view",
@ -85,6 +85,13 @@
"showHidden": "Show hidden articles", "showHidden": "Show hidden articles",
"manageSources": "Manage sources" "manageSources": "Manage sources"
}, },
"searchEngine": {
"name": "Search engine",
"google": "Google",
"bing": "Bing",
"baidu": "Baidu",
"duckduckgo": "DuckDuckGo"
},
"settings": { "settings": {
"writeError": "An error has occurred while writing the file.", "writeError": "An error has occurred while writing the file.",
"name": "Settings", "name": "Settings",

View File

@ -64,7 +64,7 @@
"copyTitle": "Copiar título", "copyTitle": "Copiar título",
"copyURL": "Copiar enlace", "copyURL": "Copiar enlace",
"copy": "Copiar", "copy": "Copiar",
"search": "Buscar \"{text}\" en Google", "search": "Buscar \"{text}\" en {engine}",
"view": "Ver", "view": "Ver",
"cardView": "Vista en modo tarjeta", "cardView": "Vista en modo tarjeta",
"listView": "Vista en modo listado", "listView": "Vista en modo listado",

View File

@ -64,7 +64,7 @@
"copyTitle": "Copier le titre", "copyTitle": "Copier le titre",
"copyURL": "Copier le lien", "copyURL": "Copier le lien",
"copy": "Copier", "copy": "Copier",
"search": "Rechercher \"{text}\" sur Google", "search": "Rechercher \"{text}\" sur {engine}",
"view": "Affichage", "view": "Affichage",
"cardView": "Vue par carte", "cardView": "Vue par carte",
"listView": "Vue par liste", "listView": "Vue par liste",

View File

@ -72,7 +72,7 @@
"copyTitle": "复制标题", "copyTitle": "复制标题",
"copyURL": "复制链接", "copyURL": "复制链接",
"copy": "复制", "copy": "复制",
"search": "使用 Google 搜索“{text}”", "search": "使用 {engine} 搜索“{text}”",
"view": "视图", "view": "视图",
"cardView": "卡片视图", "cardView": "卡片视图",
"listView": "列表视图", "listView": "列表视图",
@ -85,6 +85,11 @@
"showHidden": "显示隐藏文章", "showHidden": "显示隐藏文章",
"manageSources": "管理订阅源" "manageSources": "管理订阅源"
}, },
"searchEngine": {
"name": "搜索引擎",
"bing": "必应",
"baidu": "百度"
},
"settings": { "settings": {
"writeError": "写入文件时发生错误", "writeError": "写入文件时发生错误",
"name": "选项", "name": "选项",

View File

@ -4,6 +4,7 @@ import { AnyAction } from "redux"
import { RootState } from "./reducer" import { RootState } from "./reducer"
import Parser from "@yang991178/rss-parser" import Parser from "@yang991178/rss-parser"
import Url from "url" import Url from "url"
import { SearchEngines } from "../schema-types"
export enum ActionStatus { export enum ActionStatus {
Request, Success, Failure, Intermediate Request, Success, Failure, Intermediate
@ -108,7 +109,30 @@ export const cutText = (s: string, length: number) => {
return (s.length <= length) ? s : s.slice(0, length) + "…" return (s.length <= length) ? s : s.slice(0, length) + "…"
} }
export const googleSearch = (text: string) => window.utils.openExternal("https://www.google.com/search?q=" + encodeURIComponent(text)) export function getSearchEngineName(engine: SearchEngines) {
switch (engine) {
case SearchEngines.Google:
return intl.get("searchEngine.google")
case SearchEngines.Bing:
return intl.get("searchEngine.bing")
case SearchEngines.Baidu:
return intl.get("searchEngine.baidu")
case SearchEngines.DuckDuckGo:
return intl.get("searchEngine.duckduckgo")
}
}
export function webSearch(text: string, engine=SearchEngines.Google) {
switch (engine) {
case SearchEngines.Google:
return window.utils.openExternal("https://www.google.com/search?q=" + encodeURIComponent(text))
case SearchEngines.Bing:
return window.utils.openExternal("https://www.bing.com/search?q=" + encodeURIComponent(text))
case SearchEngines.Baidu:
return window.utils.openExternal("https://www.baidu.com/s?wd=" + encodeURIComponent(text))
case SearchEngines.DuckDuckGo:
return window.utils.openExternal("https://duckduckgo.com/?q=" + encodeURIComponent(text))
}
}
export function mergeSortedArrays<T>(a: T[], b: T[], cmp: ((x: T, y: T) => number)): T[] { export function mergeSortedArrays<T>(a: T[], b: T[], cmp: ((x: T, y: T) => number)): T[] {
let merged = new Array<T>() let merged = new Array<T>()