diff --git a/.github/workflows/release-main.yml b/.github/workflows/release-main.yml
index c7663b0..90e8a1a 100644
--- a/.github/workflows/release-main.yml
+++ b/.github/workflows/release-main.yml
@@ -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
diff --git a/package-lock.json b/package-lock.json
index 0851e42..bfbb1dd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "fluent-reader",
- "version": "0.9.1",
+ "version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index c68f581..a8c15f0 100644
--- a/package.json
+++ b/package.json
@@ -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": {
diff --git a/src/components/context-menu.tsx b/src/components/context-menu.tsx
index 4fae212..b92c574 100644
--- a/src/components/context-menu.tsx
+++ b/src/components/context-menu.tsx
@@ -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) => (
+ { this.state.existing && }
>
}
diff --git a/src/components/settings/services/fever.tsx b/src/components/settings/services/fever.tsx
index 9cc9144..da42b36 100644
--- a/src/components/settings/services/fever.tsx
+++ b/src/components/settings/services/fever.tsx
@@ -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
+ { this.state.existing && }
>
}
diff --git a/src/components/settings/services/greader.tsx b/src/components/settings/services/greader.tsx
index 8300e6a..8df9754 100644
--- a/src/components/settings/services/greader.tsx
+++ b/src/components/settings/services/greader.tsx
@@ -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
+ { this.state.existing && }
>
}
diff --git a/src/components/settings/services/inoreader.tsx b/src/components/settings/services/inoreader.tsx
index a58136f..89ff723 100644
--- a/src/components/settings/services/inoreader.tsx
+++ b/src/components/settings/services/inoreader.tsx
@@ -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
+ { this.state.existing && }
>
}
diff --git a/src/components/settings/services/lite-exporter.tsx b/src/components/settings/services/lite-exporter.tsx
new file mode 100644
index 0000000..9aebaf3
--- /dev/null
+++ b/src/components/settings/services/lite-exporter.tsx
@@ -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 = (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
+ <>>}
+ menuProps={menuProps} />
+
+}
+
+export default LiteExporter
\ No newline at end of file
diff --git a/src/scripts/i18n/en-US.json b/src/scripts/i18n/en-US.json
index 54a47b9..67b7841 100644
--- a/src/scripts/i18n/en-US.json
+++ b/src/scripts/i18n/en-US.json
@@ -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",
diff --git a/src/scripts/i18n/zh-CN.json b/src/scripts/i18n/zh-CN.json
index c61e1f4..b1ba45d 100644
--- a/src/scripts/i18n/zh-CN.json
+++ b/src/scripts/i18n/zh-CN.json
@@ -200,7 +200,8 @@
"importGroups": "导入分组",
"failure": "连接到服务时出错",
"failureHint": "请检查服务配置或网络连接",
- "fetchUnlimited": "无限制(不建议)"
+ "fetchUnlimited": "无限制(不建议)",
+ "exportToLite": "导出至 Fluent Reader Lite"
},
"app": {
"cleanup": "清理",
diff --git a/src/scripts/i18n/zh-TW.json b/src/scripts/i18n/zh-TW.json
index 2c3b949..74d49d1 100644
--- a/src/scripts/i18n/zh-TW.json
+++ b/src/scripts/i18n/zh-TW.json
@@ -200,7 +200,8 @@
"importGroups": "匯入分組",
"failure": "連線到服務時出錯",
"failureHint": "請檢查服務配置或網路連線",
- "fetchUnlimited": "無限制(不建議)"
+ "fetchUnlimited": "無限制(不建議)",
+ "exportToLite": "匯出至 Fluent Reader Lite"
},
"app": {
"cleanup": "清理",
diff --git a/src/scripts/settings.ts b/src/scripts/settings.ts
index 9e74b36..d2970d4 100644
--- a/src/scripts/settings.ts
+++ b/src/scripts/settings.ts
@@ -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((resolve, reject) => {
req.onsuccess = () => resolve()
req.onerror = () => reject()
}))
diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts
index 91400e8..e594aa7 100644
--- a/src/scripts/utils.ts
+++ b/src/scripts/utils.ts
@@ -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