mirror of
https://github.com/yang991178/fluent-reader.git
synced 2025-02-07 15:28:40 +01:00
commit
7d2860fda1
2
.github/workflows/release-main.yml
vendored
2
.github/workflows/release-main.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }} Beta
|
||||
release_name: Fluent Reader v${{ steps.package-version.outputs.current-version }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fluent-reader",
|
||||
"version": "0.9.1",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fluent-reader",
|
||||
"version": "0.9.1",
|
||||
"version": "1.0.0",
|
||||
"description": "Modern desktop RSS reader",
|
||||
"main": "./dist/electron.js",
|
||||
"scripts": {
|
||||
|
@ -40,7 +40,7 @@ export const shareSubmenu = (item: RSSItem): IContextualMenuItem[] => [
|
||||
{ key: "qr", url: item.link, onRender: renderShareQR }
|
||||
]
|
||||
|
||||
const renderShareQR = (item: IContextualMenuItem) => (
|
||||
export const renderShareQR = (item: IContextualMenuItem) => (
|
||||
<div className="qr-container">
|
||||
<QRCode
|
||||
value={item.url}
|
||||
|
@ -7,6 +7,7 @@ import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
||||
MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||
import DangerButton from "../../utils/danger-button"
|
||||
import { urlTest } from "../../../scripts/utils"
|
||||
import LiteExporter from "./lite-exporter"
|
||||
|
||||
type FeedbinConfigsTabState = {
|
||||
existing: boolean
|
||||
@ -173,6 +174,7 @@ class FeedbinConfigsTab extends React.Component<ServiceConfigsTabProps, FeedbinC
|
||||
}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||
</Stack>
|
||||
</>
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import { SyncService } from "../../../schema-types"
|
||||
import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||
import DangerButton from "../../utils/danger-button"
|
||||
import { urlTest } from "../../../scripts/utils"
|
||||
import LiteExporter from "./lite-exporter"
|
||||
|
||||
type FeverConfigsTabState = {
|
||||
existing: boolean
|
||||
@ -173,6 +174,7 @@ class FeverConfigsTab extends React.Component<ServiceConfigsTabProps, FeverConfi
|
||||
}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||
</Stack>
|
||||
</>
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { SyncService } from "../../../schema-types"
|
||||
import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||
import DangerButton from "../../utils/danger-button"
|
||||
import { urlTest } from "../../../scripts/utils"
|
||||
import LiteExporter from "./lite-exporter"
|
||||
|
||||
type GReaderConfigsTabState = {
|
||||
existing: boolean
|
||||
@ -173,6 +174,7 @@ class GReaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReaderC
|
||||
}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||
</Stack>
|
||||
</>
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { SyncService } from "../../../schema-types"
|
||||
import { Stack, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
||||
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton, Link } from "@fluentui/react"
|
||||
import DangerButton from "../../utils/danger-button"
|
||||
import LiteExporter from "./lite-exporter"
|
||||
|
||||
type GReaderConfigsTabState = {
|
||||
existing: boolean
|
||||
@ -225,6 +226,7 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
||||
}
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||
</Stack>
|
||||
</>
|
||||
}
|
||||
|
73
src/components/settings/services/lite-exporter.tsx
Normal file
73
src/components/settings/services/lite-exporter.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import * as React from "react"
|
||||
import intl from "react-intl-universal"
|
||||
import { Stack, ContextualMenuItemType, DefaultButton, IContextualMenuProps, DirectionalHint } from "@fluentui/react"
|
||||
import { ServiceConfigs, SyncService } from "../../../schema-types"
|
||||
import { renderShareQR } from "../../context-menu"
|
||||
import { platformCtrl } from "../../../scripts/utils"
|
||||
import { FeverConfigs } from "../../../scripts/models/services/fever"
|
||||
import { GReaderConfigs } from "../../../scripts/models/services/greader"
|
||||
import { FeedbinConfigs } from "../../../scripts/models/services/feedbin"
|
||||
|
||||
type LiteExporterProps = {
|
||||
serviceConfigs: ServiceConfigs
|
||||
}
|
||||
|
||||
const LEARN_MORE_URL = "https://github.com/yang991178/fluent-reader/wiki/Support#mobile-app"
|
||||
|
||||
const LiteExporter: React.FunctionComponent<LiteExporterProps> = (props) => {
|
||||
let url = "https://hyliu.me/fr2l/?"
|
||||
const params = new URLSearchParams()
|
||||
switch (props.serviceConfigs.type) {
|
||||
case SyncService.Fever: {
|
||||
const configs = props.serviceConfigs as FeverConfigs
|
||||
params.set("t", "f")
|
||||
params.set("e", configs.endpoint)
|
||||
params.set("u", configs.username)
|
||||
params.set("k", configs.apiKey)
|
||||
break
|
||||
}
|
||||
case SyncService.GReader:
|
||||
case SyncService.Inoreader: {
|
||||
const configs = props.serviceConfigs as GReaderConfigs
|
||||
params.set("t", configs.type == SyncService.GReader ? "g" : "i")
|
||||
params.set("e", configs.endpoint)
|
||||
params.set("u", configs.username)
|
||||
params.set("p", btoa(configs.password))
|
||||
if (configs.inoreaderId) {
|
||||
params.set("i", configs.inoreaderId)
|
||||
params.set("k", configs.inoreaderKey)
|
||||
}
|
||||
break
|
||||
}
|
||||
case SyncService.Feedbin: {
|
||||
const configs = props.serviceConfigs as FeedbinConfigs
|
||||
params.set("t", "fb")
|
||||
params.set("e", configs.endpoint)
|
||||
params.set("u", configs.username)
|
||||
params.set("p", btoa(configs.password))
|
||||
break
|
||||
}
|
||||
}
|
||||
url += params.toString()
|
||||
const menuProps: IContextualMenuProps = {
|
||||
directionalHint: DirectionalHint.bottomCenter,
|
||||
items: [
|
||||
{ key: "qr", url: url, onRender: renderShareQR },
|
||||
{ key: "divider_1", itemType: ContextualMenuItemType.Divider },
|
||||
{
|
||||
key: "openInBrowser",
|
||||
text: intl.get("rules.help"),
|
||||
iconProps: { iconName: "NavigateExternalInline" },
|
||||
onClick: e => { window.utils.openExternal(LEARN_MORE_URL, platformCtrl(e)) }
|
||||
},
|
||||
]
|
||||
}
|
||||
return <Stack style={{marginTop: 32}}>
|
||||
<DefaultButton
|
||||
text={intl.get("service.exportToLite")}
|
||||
onRenderMenuIcon={() => <></>}
|
||||
menuProps={menuProps} />
|
||||
</Stack>
|
||||
}
|
||||
|
||||
export default LiteExporter
|
@ -202,7 +202,8 @@
|
||||
"importGroups": "Import groups",
|
||||
"failure": "Cannot connect to service",
|
||||
"failureHint": "Please check the service configuration or network status.",
|
||||
"fetchUnlimited": "Unlimited (not recommended)"
|
||||
"fetchUnlimited": "Unlimited (not recommended)",
|
||||
"exportToLite": "Export to Fluent Reader Lite"
|
||||
},
|
||||
"app": {
|
||||
"cleanup": "Clean up",
|
||||
|
@ -200,7 +200,8 @@
|
||||
"importGroups": "导入分组",
|
||||
"failure": "连接到服务时出错",
|
||||
"failureHint": "请检查服务配置或网络连接",
|
||||
"fetchUnlimited": "无限制(不建议)"
|
||||
"fetchUnlimited": "无限制(不建议)",
|
||||
"exportToLite": "导出至 Fluent Reader Lite"
|
||||
},
|
||||
"app": {
|
||||
"cleanup": "清理",
|
||||
|
@ -200,7 +200,8 @@
|
||||
"importGroups": "匯入分組",
|
||||
"failure": "連線到服務時出錯",
|
||||
"failureHint": "請檢查服務配置或網路連線",
|
||||
"fetchUnlimited": "無限制(不建議)"
|
||||
"fetchUnlimited": "無限制(不建議)",
|
||||
"exportToLite": "匯出至 Fluent Reader Lite"
|
||||
},
|
||||
"app": {
|
||||
"cleanup": "清理",
|
||||
|
@ -94,7 +94,7 @@ export async function importAll() {
|
||||
let requests = Object.entries(configs.nedb).map(([key, value]) => {
|
||||
return objectStore.put(value, key)
|
||||
})
|
||||
let promises = requests.map(req => new Promise((resolve, reject) => {
|
||||
let promises = requests.map(req => new Promise<void>((resolve, reject) => {
|
||||
req.onsuccess = () => resolve()
|
||||
req.onerror = () => reject()
|
||||
}))
|
||||
|
@ -29,7 +29,7 @@ const rssParser = new Parser({
|
||||
})
|
||||
|
||||
const CHARSET_RE = /charset=([^()<>@,;:\"/[\]?.=\s]*)/i
|
||||
const XML_ENCODING_RE = /^<\?xml.+encoding="(.+)".*?\?>/i
|
||||
const XML_ENCODING_RE = /^<\?xml.+encoding="(.+?)".*?\?>/i
|
||||
export async function decodeFetchResponse(response: Response, isHTML = false) {
|
||||
const buffer = await response.arrayBuffer()
|
||||
let ctype = response.headers.has("content-type") && response.headers.get("content-type")
|
||||
@ -122,7 +122,7 @@ export function htmlDecode(input: string) {
|
||||
}
|
||||
|
||||
export const urlTest = (s: string) =>
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi.test(s)
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,63}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi.test(s)
|
||||
|
||||
export const getWindowBreakpoint = () => window.outerWidth >= 1440
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user