Skip to content

Commit 1e87917

Browse files
committed
feat: add support for customized Ipv4 list, close #17
1 parent 9155415 commit 1e87917

File tree

9 files changed

+146
-35
lines changed

9 files changed

+146
-35
lines changed

apis/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { userSettingsStore } from '@/store/UserSettings';
12
import { getInitialCfIpResponse } from "./../screens/TestRunScreen/utils/index";
23
import { RequestStatus } from "@/typings/index";
34
import { getCfIpV4List, getRandomItems } from "@/utils/index";
@@ -148,6 +149,6 @@ export const getCfNodesDownloadTestTime = (
148149
);
149150
};
150151
export const getRandomCfIpList = (totalCount: number) => {
151-
const ipList = getRandomItems(getCfIpV4List(), totalCount);
152+
const ipList = getRandomItems(getCfIpV4List(userSettingsStore.getCurIpv4ListText()), totalCount);
152153
return ipList;
153154
};

components/Themed.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ export function TextInput(props: TextInputProps) {
4949
const { style, lightColor, darkColor, ...otherProps } = props;
5050
const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
5151
const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
52-
53-
return <DefaultTextInput style={[{ backgroundColor,color }, style]} {...otherProps} />;
52+
const borderColor = color;
53+
return <DefaultTextInput style={[{ backgroundColor,color,borderColor }, style]} {...otherProps} />;
5454
}

lang/en-us.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"downloadSpeed": "Download Speed",
99
"showAllData": "Show All Data",
1010
"showSortedTop": "Show Sorted Top",
11-
"getPermFailed": "Get Permissions Failed"
11+
"getPermFailed": "Get Permissions Failed",
12+
"cancel": "Cancel",
13+
"confirm": "Confirm",
14+
"reset": "Reset"
1215
},
1316
"testRun": {
1417
"title": "Test Run",
@@ -32,7 +35,8 @@
3235
"testConfig": {
3336
"title": "Test Config",
3437
"clearHistoryStatistics": "Clear history statistics",
35-
"saveAllDataToDevice": "Save all data to device"
38+
"saveAllDataToDevice": "Save all data to device",
39+
"customizeCfIpv4List": "Customize Cloudflare Ipv4 list"
3640
},
3741
"update": {
3842
"title": "Update available",

lang/zh-cn.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"downloadSpeed": "下载速度",
99
"showAllData": "展示所有数据",
1010
"showSortedTop": "展示排序后的前",
11-
"getPermFailed": "获取权限失败"
11+
"getPermFailed": "获取权限失败",
12+
"cancel": "取消",
13+
"confirm": "确定",
14+
"reset": "重置"
1215
},
1316
"testRun": {
1417
"title": "运行测试",
@@ -32,7 +35,8 @@
3235
"testConfig": {
3336
"title": "测试配置",
3437
"clearHistoryStatistics": "清除历史统计数据",
35-
"saveAllDataToDevice": "保存数据到设备"
38+
"saveAllDataToDevice": "保存数据到设备",
39+
"customizeCfIpv4List": "自定义 Cloudflare Ipv4 列表"
3640
},
3741
"update": {
3842
"title": "发现新版本",
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { TextInput } from "@/components/Themed";
2+
import { AppI18n } from "@/localize";
3+
import { userSettingsStore } from "@/store/UserSettings";
4+
import * as React from "react";
5+
import { Button, Dialog, Portal } from "react-native-paper";
6+
import { SettingButton } from "./SettingButton";
7+
8+
export function CfIpv4CustomizeDialog() {
9+
const [visible, setVisible] = React.useState(false);
10+
const [tempIpv4List, setTempIpv4List] = React.useState(
11+
userSettingsStore.getCurIpv4ListText()
12+
);
13+
14+
const showModal = () => setVisible(true);
15+
const onDismiss = () => {
16+
setVisible(false);
17+
clearTempData();
18+
};
19+
const clearTempData = () =>
20+
setTempIpv4List(() => userSettingsStore.getCurIpv4ListText());
21+
22+
const onReset = () => {
23+
setTempIpv4List(() => userSettingsStore.getDefaultIpv4ListText());
24+
};
25+
const onConfirmChangeIpList = () => {
26+
userSettingsStore.changeCfIpv4ListText(tempIpv4List);
27+
onDismiss();
28+
};
29+
const onChangeIpList = (v: string) => {
30+
setTempIpv4List(() => v);
31+
};
32+
const title = AppI18n.t("testConfig.customizeCfIpv4List");
33+
return (
34+
<React.Fragment>
35+
<SettingButton onPress={showModal} label={title}></SettingButton>
36+
<Portal>
37+
<Dialog visible={visible} onDismiss={onDismiss} dismissable={false}>
38+
<Dialog.Title>{title}</Dialog.Title>
39+
<Dialog.Content>
40+
<TextInput
41+
onChangeText={onChangeIpList}
42+
value={tempIpv4List}
43+
multiline={true}
44+
style={{ borderWidth: 1, paddingHorizontal: 8 }}
45+
></TextInput>
46+
</Dialog.Content>
47+
<Dialog.Actions>
48+
<Button onPress={onReset} mode="contained">
49+
{AppI18n.t("general.reset")}
50+
</Button>
51+
<Button
52+
onPress={onDismiss}
53+
mode="contained"
54+
style={{ marginHorizontal: 16 }}
55+
>
56+
{AppI18n.t("general.cancel")}
57+
</Button>
58+
<Button onPress={onConfirmChangeIpList} mode="contained">
59+
{AppI18n.t("general.confirm")}
60+
</Button>
61+
</Dialog.Actions>
62+
</Dialog>
63+
</Portal>
64+
</React.Fragment>
65+
);
66+
}

screens/TestConfigScreen/components/ConfigList.tsx

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,13 @@ import { observer } from "mobx-react";
88
import { testStatisticsStore } from "@/store/TestStatistics";
99
import { AppI18n } from "@/localize";
1010
import { useTheme } from "@react-navigation/native";
11+
import { CfIpv4CustomizeDialog } from "./CfIpv4CustomizeDialog";
12+
import { SettingButton } from "./SettingButton";
1113

1214
export const ConfigList = observer(() => (
1315
<InternalConfigList userSettings={{ ...userSettingsStore.userSetting }} />
1416
));
15-
function SettingButton(props: { onPress: () => void; label: string }) {
16-
const { onPress, label } = props;
17-
const { colors } = useTheme();
1817

19-
return (
20-
<View style={styles.item}>
21-
<Button
22-
mode="text"
23-
uppercase={false}
24-
style={{
25-
width: "100%",
26-
}}
27-
labelStyle={{
28-
color: colors.text,
29-
fontFamily: "inherit",
30-
}}
31-
contentStyle={{
32-
marginLeft: -16,
33-
alignSelf: "flex-start",
34-
}}
35-
onPress={onPress}
36-
>
37-
{label}
38-
</Button>
39-
</View>
40-
);
41-
}
4218
function InternalConfigList({ userSettings }: { userSettings: UserSetting }) {
4319
const { isSaveDataToDevice } = userSettings;
4420

@@ -69,6 +45,7 @@ function InternalConfigList({ userSettings }: { userSettings: UserSetting }) {
6945
onPress={() => testStatisticsStore.clear()}
7046
label={AppI18n.t("testConfig.clearHistoryStatistics")}
7147
></SettingButton>
48+
<CfIpv4CustomizeDialog></CfIpv4CustomizeDialog>
7249
</View>
7350
</View>
7451
);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { View } from "@/components/Themed";
2+
import { useTheme } from "@react-navigation/native";
3+
import { Button } from "react-native-paper";
4+
import { StyleSheet } from "react-native";
5+
6+
export function SettingButton(props: { onPress: () => void; label: string }) {
7+
const { onPress, label } = props;
8+
const { colors } = useTheme();
9+
10+
return (
11+
<View style={styles.item}>
12+
<Button
13+
mode="text"
14+
uppercase={false}
15+
style={{
16+
width: "100%",
17+
}}
18+
labelStyle={{
19+
color: colors.text,
20+
fontFamily: "inherit",
21+
}}
22+
contentStyle={{
23+
marginLeft: -16,
24+
alignSelf: "flex-start",
25+
}}
26+
onPress={onPress}
27+
>
28+
{label}
29+
</Button>
30+
</View>
31+
);
32+
}
33+
34+
const styles = StyleSheet.create({
35+
item: {
36+
height: 40,
37+
flexDirection: "row",
38+
alignItems: "center",
39+
justifyContent: "space-between",
40+
},
41+
});

store/UserSettings.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1+
import { CfIpV4Text } from "@/constants/CfIpListV4";
12
import { action, makeObservable, observable, reaction } from "mobx";
23
import { UserSettingsStorageSync } from "./UserSettingsStorageSync";
34
export type UserSetting = {
45
isSaveDataToDevice: boolean;
6+
defaultCfIpv4Text: string;
7+
customizedCfIpv4Text: string;
58
};
69
class UserSettings {
710
private defaultUserSetting: UserSetting = {
811
isSaveDataToDevice: false,
12+
defaultCfIpv4Text: CfIpV4Text,
13+
customizedCfIpv4Text: CfIpV4Text,
914
} as const;
1015
readonly userSetting: UserSetting = { ...this.defaultUserSetting };
1116
private storageSync: UserSettingsStorageSync;
1217
constructor() {
1318
makeObservable(this, {
1419
userSetting: observable,
1520
changeUserSettings: action,
21+
changeCfIpv4ListText: action,
22+
resetCfIpv4ListText: action,
1623
});
1724
this.storageSync = new UserSettingsStorageSync(
1825
this.userSetting,
@@ -45,6 +52,18 @@ class UserSettings {
4552
}
4653
);
4754
}
55+
public changeCfIpv4ListText(customizedCfIpv4Text: string) {
56+
this.userSetting.customizedCfIpv4Text = customizedCfIpv4Text;
57+
}
58+
public resetCfIpv4ListText() {
59+
this.userSetting.customizedCfIpv4Text = this.userSetting.defaultCfIpv4Text;
60+
}
61+
public getCurIpv4ListText() {
62+
return this.userSetting.customizedCfIpv4Text;
63+
}
64+
public getDefaultIpv4ListText() {
65+
return this.userSetting.defaultCfIpv4Text
66+
}
4867
}
4968

5069
const userSettingsStore = new UserSettings();

utils/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { CfIpV4Text } from "@/constants/CfIpListV4";
21
import { Netmask } from "netmask";
32
export const getRandomItems = <T extends unknown[]>(
43
list: T,
@@ -12,7 +11,7 @@ export const getRandomItems = <T extends unknown[]>(
1211
return result as T;
1312
};
1413

15-
export const getCfIpV4List = () => {
14+
export const getCfIpV4List = (CfIpV4Text: string) => {
1615
const resultList = CfIpV4Text.split("\n")
1716
.map((v) => v.trim())
1817
.filter((v) => v)

0 commit comments

Comments
 (0)