add exporting to mobile app
This commit is contained in:
parent
09bb6cbd07
commit
b336260d0c
|
@ -32,7 +32,7 @@ jobs:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
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
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "fluent-reader",
|
"name": "fluent-reader",
|
||||||
"version": "0.9.1",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "fluent-reader",
|
"name": "fluent-reader",
|
||||||
"version": "0.9.1",
|
"version": "1.0.0",
|
||||||
"description": "Modern desktop RSS reader",
|
"description": "Modern desktop RSS reader",
|
||||||
"main": "./dist/electron.js",
|
"main": "./dist/electron.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -40,7 +40,7 @@ export const shareSubmenu = (item: RSSItem): IContextualMenuItem[] => [
|
||||||
{ key: "qr", url: item.link, onRender: renderShareQR }
|
{ key: "qr", url: item.link, onRender: renderShareQR }
|
||||||
]
|
]
|
||||||
|
|
||||||
const renderShareQR = (item: IContextualMenuItem) => (
|
export const renderShareQR = (item: IContextualMenuItem) => (
|
||||||
<div className="qr-container">
|
<div className="qr-container">
|
||||||
<QRCode
|
<QRCode
|
||||||
value={item.url}
|
value={item.url}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
||||||
MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||||
import DangerButton from "../../utils/danger-button"
|
import DangerButton from "../../utils/danger-button"
|
||||||
import { urlTest } from "../../../scripts/utils"
|
import { urlTest } from "../../../scripts/utils"
|
||||||
|
import LiteExporter from "./lite-exporter"
|
||||||
|
|
||||||
type FeedbinConfigsTabState = {
|
type FeedbinConfigsTabState = {
|
||||||
existing: boolean
|
existing: boolean
|
||||||
|
@ -173,6 +174,7 @@ class FeedbinConfigsTab extends React.Component<ServiceConfigsTabProps, FeedbinC
|
||||||
}
|
}
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||||
</Stack>
|
</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 { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||||
import DangerButton from "../../utils/danger-button"
|
import DangerButton from "../../utils/danger-button"
|
||||||
import { urlTest } from "../../../scripts/utils"
|
import { urlTest } from "../../../scripts/utils"
|
||||||
|
import LiteExporter from "./lite-exporter"
|
||||||
|
|
||||||
type FeverConfigsTabState = {
|
type FeverConfigsTabState = {
|
||||||
existing: boolean
|
existing: boolean
|
||||||
|
@ -173,6 +174,7 @@ class FeverConfigsTab extends React.Component<ServiceConfigsTabProps, FeverConfi
|
||||||
}
|
}
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||||
</Stack>
|
</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 { Stack, Icon, Label, TextField, PrimaryButton, DefaultButton, Checkbox, MessageBar, MessageBarType, Dropdown, IDropdownOption } from "@fluentui/react"
|
||||||
import DangerButton from "../../utils/danger-button"
|
import DangerButton from "../../utils/danger-button"
|
||||||
import { urlTest } from "../../../scripts/utils"
|
import { urlTest } from "../../../scripts/utils"
|
||||||
|
import LiteExporter from "./lite-exporter"
|
||||||
|
|
||||||
type GReaderConfigsTabState = {
|
type GReaderConfigsTabState = {
|
||||||
existing: boolean
|
existing: boolean
|
||||||
|
@ -173,6 +174,7 @@ class GReaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReaderC
|
||||||
}
|
}
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { SyncService } from "../../../schema-types"
|
||||||
import { Stack, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
import { Stack, Label, TextField, PrimaryButton, DefaultButton, Checkbox,
|
||||||
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton, Link } from "@fluentui/react"
|
MessageBar, MessageBarType, Dropdown, IDropdownOption, MessageBarButton, Link } from "@fluentui/react"
|
||||||
import DangerButton from "../../utils/danger-button"
|
import DangerButton from "../../utils/danger-button"
|
||||||
|
import LiteExporter from "./lite-exporter"
|
||||||
|
|
||||||
type GReaderConfigsTabState = {
|
type GReaderConfigsTabState = {
|
||||||
existing: boolean
|
existing: boolean
|
||||||
|
@ -225,6 +226,7 @@ class InoreaderConfigsTab extends React.Component<ServiceConfigsTabProps, GReade
|
||||||
}
|
}
|
||||||
</Stack.Item>
|
</Stack.Item>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
{ this.state.existing && <LiteExporter serviceConfigs={this.props.configs} /> }
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
"importGroups": "Import groups",
|
||||||
"failure": "Cannot connect to service",
|
"failure": "Cannot connect to service",
|
||||||
"failureHint": "Please check the service configuration or network status.",
|
"failureHint": "Please check the service configuration or network status.",
|
||||||
"fetchUnlimited": "Unlimited (not recommended)"
|
"fetchUnlimited": "Unlimited (not recommended)",
|
||||||
|
"exportToLite": "Export to Fluent Reader Lite"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"cleanup": "Clean up",
|
"cleanup": "Clean up",
|
||||||
|
|
|
@ -200,7 +200,8 @@
|
||||||
"importGroups": "导入分组",
|
"importGroups": "导入分组",
|
||||||
"failure": "连接到服务时出错",
|
"failure": "连接到服务时出错",
|
||||||
"failureHint": "请检查服务配置或网络连接",
|
"failureHint": "请检查服务配置或网络连接",
|
||||||
"fetchUnlimited": "无限制(不建议)"
|
"fetchUnlimited": "无限制(不建议)",
|
||||||
|
"exportToLite": "导出至 Fluent Reader Lite"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"cleanup": "清理",
|
"cleanup": "清理",
|
||||||
|
|
|
@ -200,7 +200,8 @@
|
||||||
"importGroups": "匯入分組",
|
"importGroups": "匯入分組",
|
||||||
"failure": "連線到服務時出錯",
|
"failure": "連線到服務時出錯",
|
||||||
"failureHint": "請檢查服務配置或網路連線",
|
"failureHint": "請檢查服務配置或網路連線",
|
||||||
"fetchUnlimited": "無限制(不建議)"
|
"fetchUnlimited": "無限制(不建議)",
|
||||||
|
"exportToLite": "匯出至 Fluent Reader Lite"
|
||||||
},
|
},
|
||||||
"app": {
|
"app": {
|
||||||
"cleanup": "清理",
|
"cleanup": "清理",
|
||||||
|
|
|
@ -94,7 +94,7 @@ export async function importAll() {
|
||||||
let requests = Object.entries(configs.nedb).map(([key, value]) => {
|
let requests = Object.entries(configs.nedb).map(([key, value]) => {
|
||||||
return objectStore.put(value, key)
|
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.onsuccess = () => resolve()
|
||||||
req.onerror = () => reject()
|
req.onerror = () => reject()
|
||||||
}))
|
}))
|
||||||
|
|
Loading…
Reference in New Issue