Feature: add sort delay button

This commit is contained in:
Dreamacro 2019-09-13 17:59:27 +08:00
parent 505e290beb
commit 8199612bc7
7 changed files with 1027 additions and 523 deletions

1417
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,58 +28,58 @@
"contributors:generate": "all-contributors generate" "contributors:generate": "all-contributors generate"
}, },
"devDependencies": { "devDependencies": {
"@babel/cli": "^7.5.5", "@babel/cli": "^7.6.0",
"@babel/core": "^7.5.5", "@babel/core": "^7.6.0",
"@babel/preset-env": "^7.5.5", "@babel/preset-env": "^7.6.0",
"@babel/preset-react": "^7.0.0", "@babel/preset-react": "^7.0.0",
"@hot-loader/react-dom": "^16.8.6", "@hot-loader/react-dom": "^16.9.0",
"@types/classnames": "^2.2.8", "@types/classnames": "^2.2.8",
"@types/lodash-es": "^4.17.3", "@types/lodash-es": "^4.17.3",
"@types/node": "^12.6.9", "@types/node": "^12.7.5",
"@types/react": "^16.8.24", "@types/react": "^16.9.2",
"@types/react-dom": "^16.8.5", "@types/react-dom": "^16.9.0",
"@types/react-router-dom": "^4.3.4", "@types/react-router-dom": "^4.3.5",
"@types/react-virtualized-auto-sizer": "^1.0.0", "@types/react-virtualized-auto-sizer": "^1.0.0",
"@types/react-window": "^1.8.0", "@types/react-window": "^1.8.1",
"autoprefixer": "^9.6.1", "autoprefixer": "^9.6.1",
"awesome-typescript-loader": "^5.2.1", "awesome-typescript-loader": "^5.2.1",
"babel-loader": "^8.0.6", "babel-loader": "^8.0.6",
"babel-preset-minify": "^0.5.0", "babel-preset-minify": "^0.5.1",
"css-loader": "^3.1.0", "css-loader": "^3.2.0",
"file-loader": "^4.1.0", "file-loader": "^4.2.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^5.0.0", "image-webpack-loader": "^6.0.0",
"mini-css-extract-plugin": "^0.8.0", "mini-css-extract-plugin": "^0.8.0",
"offline-plugin": "^5.0.7", "offline-plugin": "^5.0.7",
"postcss-loader": "^3.0.0", "postcss-loader": "^3.0.0",
"react-hot-loader": "^4.12.10", "react-hot-loader": "^4.12.13",
"sass": "^1.22.9", "sass": "^1.22.12",
"sass-loader": "^7.1.0", "sass-loader": "^8.0.0",
"style-loader": "^0.23.1", "style-loader": "^1.0.0",
"stylelint": "^10.1.0", "stylelint": "^10.1.0",
"stylelint-config-standard": "^18.3.0", "stylelint-config-standard": "^18.3.0",
"stylelint-webpack-plugin": "^0.10.5", "stylelint-webpack-plugin": "^0.10.5",
"terser-webpack-plugin": "^1.4.1", "terser-webpack-plugin": "^2.0.1",
"tslint": "^5.18.0", "tslint": "^5.20.0",
"tslint-config-standard": "^8.0.1", "tslint-config-standard": "^8.0.1",
"tslint-loader": "^3.6.0", "tslint-loader": "^3.6.0",
"typescript": "^3.5.3", "typescript": "^3.6.3",
"webpack": "^4.39.1", "webpack": "^4.40.1",
"webpack-cli": "^3.3.6", "webpack-cli": "^3.3.8",
"webpack-dev-middleware": "^3.7.0", "webpack-dev-middleware": "^3.7.1",
"webpack-dev-server": "^3.7.2", "webpack-dev-server": "^3.8.0",
"webpack-merge": "^4.2.1", "webpack-merge": "^4.2.2",
"webpack-pwa-manifest": "^4.0.0" "webpack-pwa-manifest": "^4.0.0"
}, },
"dependencies": { "dependencies": {
"axios": "^0.19.0", "axios": "^0.19.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"dayjs": "^1.8.15", "dayjs": "^1.8.16",
"eventemitter3": "^4.0.0", "eventemitter3": "^4.0.0",
"immer": "^3.2.0", "immer": "^4.0.0",
"lodash-es": "^4.17.15", "lodash-es": "^4.17.15",
"react": "^16.8.6", "react": "^16.9.0",
"react-dom": "^16.8.6", "react-dom": "^16.9.0",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.0.1",
"react-virtualized-auto-sizer": "^1.0.2", "react-virtualized-auto-sizer": "^1.0.2",
"react-window": "^1.8.5", "react-window": "^1.8.5",

View File

@ -1,6 +1,7 @@
import React, { useState, useMemo, useLayoutEffect, useEffect } from 'react' import React, { useState, useMemo, useLayoutEffect, useEffect } from 'react'
import classnames from 'classnames' import classnames from 'classnames'
import { BaseComponentProps } from '@models' import { BaseComponentProps } from '@models'
import { containers } from '@stores'
import { getProxyDelay, Proxy as IProxy } from '@lib/request' import { getProxyDelay, Proxy as IProxy } from '@lib/request'
import EE, { Action } from '@lib/event' import EE, { Action } from '@lib/event'
import { isClashX, jsBridge } from '@lib/jsBridge' import { isClashX, jsBridge } from '@lib/jsBridge'
@ -31,10 +32,14 @@ async function getDelay (name: string) {
export function Proxy (props: ProxyProps) { export function Proxy (props: ProxyProps) {
const { config, className } = props const { config, className } = props
const [delay, setDelay] = useState(0) const [delay, setDelay] = useState(0)
const { updateDelay } = containers.useData()
async function speedTest () { async function speedTest () {
const [delay, err] = await to(getDelay(config.name)) const [delay, err] = await to(getDelay(config.name))
setDelay(err ? 0 : delay)
const validDelay = err ? 0 : delay
setDelay(validDelay)
updateDelay(config.name, validDelay)
} }
useEffect(() => { useEffect(() => {

View File

@ -1,11 +1,30 @@
import React, { useLayoutEffect } from 'react' import React, { useLayoutEffect, useState, useMemo } from 'react'
import EE from '@lib/event' import EE from '@lib/event'
import { Card, Header, Icon } from '@components' import { Card, Header, Icon } from '@components'
import { containers } from '@stores' import { containers } from '@stores'
import * as API from '@lib/request'
import { Proxy, Group } from './components' import { Proxy, Group } from './components'
import './style.scss' import './style.scss'
enum sortType {
None,
Asc,
Desc
}
const sortMap = {
[sortType.None]: 'sort',
[sortType.Asc]: 'sort-ascending',
[sortType.Desc]: 'sort-descending'
}
function compareDesc (a: API.Proxy, b: API.Proxy) {
const lastDelayA = a.history.length ? a.history.slice(-1)[0].delay : 0
const lastDelayB = b.history.length ? b.history.slice(-1)[0].delay : 0
return (lastDelayB || Number.MAX_SAFE_INTEGER) - (lastDelayA || Number.MAX_SAFE_INTEGER)
}
export default function Proxies () { export default function Proxies () {
const { data, fetch } = containers.useData() const { data, fetch } = containers.useData()
const { useTranslation } = containers.useI18n() const { useTranslation } = containers.useI18n()
@ -14,11 +33,26 @@ export default function Proxies () {
useLayoutEffect(() => { useLayoutEffect(() => {
fetch() fetch()
}, []) }, [])
function handleNotitySpeedTest () { function handleNotitySpeedTest () {
EE.notifySpeedTest() EE.notifySpeedTest()
} }
const [sort, setSort] = useState(sortType.None)
const proxies = useMemo(() => {
console.log(1)
switch (sort) {
case sortType.Desc:
return data.proxy.slice().sort((a, b) => compareDesc(a, b))
case sortType.Asc:
return data.proxy.slice().sort((a, b) => -1 * compareDesc(a, b))
default:
return data.proxy.slice()
}
}, [sort, data])
function handleSort () {
setSort((sort + 1) % 3)
}
return ( return (
<div className="page"> <div className="page">
<div className="proxies-container"> <div className="proxies-container">
@ -37,12 +71,13 @@ export default function Proxies () {
</div> </div>
<div className="proxies-container"> <div className="proxies-container">
<Header title={t('title')}> <Header title={t('title')}>
<Icon type="speed" size={20} /> <Icon className="proxies-action-icon" type={sortMap[sort]} onClick={handleSort} size={20} />
<Icon className="proxies-action-icon" type="speed" size={20} />
<span className="proxies-speed-test" onClick={handleNotitySpeedTest}>{t('speedTestText')}</span> <span className="proxies-speed-test" onClick={handleNotitySpeedTest}>{t('speedTestText')}</span>
</Header> </Header>
<ul className="proxies-list"> <ul className="proxies-list">
{ {
data.proxy.map(p => ( proxies.map(p => (
<li key={p.name}> <li key={p.name}>
<Proxy config={p} /> <Proxy config={p} />
</li> </li>

View File

@ -57,6 +57,10 @@
margin: 20px 0; margin: 20px 0;
} }
.proxies-container .proxies-action-icon {
margin-left: 10px;
}
.proxies-speed-test { .proxies-speed-test {
line-height: 32px; line-height: 32px;
margin: 0 2px 0 6px; margin: 0 2px 0 6px;

View File

@ -7,7 +7,7 @@ import { setLocalStorageItem, partition, to } from '@lib/helper'
import { useI18n } from '@i18n' import { useI18n } from '@i18n'
function useData () { function useData () {
const { value: data, setSingle, setMulti } = useObject<Models.Data>({ const { value: data, setSingle, setMulti, set } = useObject<Models.Data>({
general: {}, general: {},
proxy: [], proxy: [],
proxyGroup: [], proxyGroup: [],
@ -58,7 +58,16 @@ function useData () {
}) })
} }
return { data, fetch, unauthorized: { visible, show, hidden } } function updateDelay (proxy: string, delay: number) {
set(draft => {
const p = draft.proxy.find(p => p.name === proxy)
if (p) {
p.history.push({ time: Date.now().toString(), delay })
}
})
}
return { data, fetch, unauthorized: { visible, show, hidden }, updateDelay }
} }
function useAPIInfo () { function useAPIInfo () {

View File

@ -6,7 +6,7 @@
@font-face { @font-face {
font-family: "clash-iconfont"; font-family: "clash-iconfont";
src: url('//at.alicdn.com/t/font_841708_6gtmjlak9k2.ttf?t=1551607902712') format('truetype'); src: url('//at.alicdn.com/t/font_841708_z4foe3sarr8.ttf?t=1567008313882') format('truetype');
} }
.clash-iconfont { .clash-iconfont {
@ -45,3 +45,9 @@
.icon-show::before { content: "\e60e"; } .icon-show::before { content: "\e60e"; }
.icon-hide::before { content: "\e60f"; } .icon-hide::before { content: "\e60f"; }
.icon-sort::before { content: "\e8b3"; }
.icon-sort-descending::before { content: "\e8b4"; }
.icon-sort-ascending::before { content: "\e8b5"; }