1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
import React from 'react';
import { connect } from './StateProvider';
import Button from './Button';
import ContentHeader from './ContentHeader';
import ProxyGroup from './ProxyGroup';
import BaseModal from './shared/BaseModal';
import Settings from './proxies/Settings';
import Equalizer from './svg/Equalizer';
import { Zap } from 'react-feather';
import ProxyProviderList from './ProxyProviderList';
import { Fab, position as fabPosition } from './shared/Fab';
import s0 from './Proxies.module.css';
import {
getDelay,
getProxyGroupNames,
getProxyProviders,
fetchProxies,
requestDelayAll,
} from '../store/proxies';
import { getClashAPIConfig } from '../store/app';
const { useState, useEffect, useCallback, useRef } = React;
function Proxies({ dispatch, groupNames, delay, proxyProviders, apiConfig }) {
const refFetchedTimestamp = useRef({});
const requestDelayAllFn = useCallback(
() => dispatch(requestDelayAll(apiConfig)),
[apiConfig, dispatch]
);
const fetchProxiesHooked = useCallback(() => {
refFetchedTimestamp.current.startAt = new Date();
dispatch(fetchProxies(apiConfig)).then(() => {
refFetchedTimestamp.current.completeAt = new Date();
});
}, [apiConfig, dispatch]);
useEffect(() => {
// fetch it now
fetchProxiesHooked();
// arm a window on focus listener to refresh it
const fn = () => {
if (
refFetchedTimestamp.current.startAt &&
new Date() - refFetchedTimestamp.current.startAt > 3e4 // 30s
) {
fetchProxiesHooked();
}
};
window.addEventListener('focus', fn, false);
return () => window.removeEventListener('focus', fn, false);
}, [fetchProxiesHooked]);
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
const closeSettingsModal = useCallback(() => {
setIsSettingsModalOpen(false);
}, []);
return (
<>
<div className={s0.topBar}>
<Button kind="minimal" onClick={() => setIsSettingsModalOpen(true)}>
<Equalizer size={16} />
</Button>
</div>
<BaseModal
isOpen={isSettingsModalOpen}
onRequestClose={closeSettingsModal}
>
<Settings />
</BaseModal>
<ContentHeader title="Proxies" />
<div>
{groupNames.map((groupName) => {
return (
<div className={s0.group} key={groupName}>
<ProxyGroup
name={groupName}
delay={delay}
apiConfig={apiConfig}
dispatch={dispatch}
/>
</div>
);
})}
</div>
<ProxyProviderList items={proxyProviders} />
<div style={{ height: 60 }} />
<Fab
icon={<Zap width={16} />}
onClick={requestDelayAllFn}
text="Test Latency"
position={fabPosition}
/>
</>
);
}
const mapState = (s) => ({
apiConfig: getClashAPIConfig(s),
groupNames: getProxyGroupNames(s),
proxyProviders: getProxyProviders(s),
delay: getDelay(s),
});
export default connect(mapState)(Proxies);
|