fix bugs
This commit is contained in:
157
components/ServerSettingsModal.tsx
Normal file
157
components/ServerSettingsModal.tsx
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Modal,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
import { saveServerDomain } from '../services/api';
|
||||||
|
|
||||||
|
const PRESETS = [
|
||||||
|
{ label: 'aa.pfgame.org', host: 'aa.pfgame.org', port: '443' },
|
||||||
|
{ label: '192.168.1.117:16000', host: '192.168.1.117', port: '16000' },
|
||||||
|
];
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
visible: boolean;
|
||||||
|
host: string;
|
||||||
|
port: string;
|
||||||
|
onHostChange: (host: string) => void;
|
||||||
|
onPortChange: (port: string) => void;
|
||||||
|
onClose: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ServerSettingsModal: React.FC<Props> = ({
|
||||||
|
visible,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
|
onHostChange,
|
||||||
|
onPortChange,
|
||||||
|
onClose,
|
||||||
|
}) => (
|
||||||
|
<Modal visible={visible} transparent animationType="fade">
|
||||||
|
<View style={styles.overlay}>
|
||||||
|
<View style={styles.box}>
|
||||||
|
<Text style={styles.title}>Server Settings</Text>
|
||||||
|
<View style={styles.presets}>
|
||||||
|
{PRESETS.map((p) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={p.label}
|
||||||
|
onPress={() => {
|
||||||
|
onHostChange(p.host);
|
||||||
|
onPortChange(p.port);
|
||||||
|
}}
|
||||||
|
style={[styles.presetBtn, host === p.host && port === p.port && styles.presetBtnActive]}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
color: host === p.host && port === p.port ? '#fff' : '#333',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{p.label}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
<Text style={styles.inputLabel}>Host</Text>
|
||||||
|
<TextInput
|
||||||
|
style={styles.textInput}
|
||||||
|
value={host}
|
||||||
|
onChangeText={onHostChange}
|
||||||
|
placeholder="192.168.1.198"
|
||||||
|
autoCapitalize="none"
|
||||||
|
/>
|
||||||
|
<Text style={styles.inputLabel}>Port</Text>
|
||||||
|
<TextInput
|
||||||
|
style={[styles.textInput, { marginBottom: 20 }]}
|
||||||
|
value={port}
|
||||||
|
onChangeText={onPortChange}
|
||||||
|
placeholder="16000"
|
||||||
|
keyboardType="number-pad"
|
||||||
|
/>
|
||||||
|
<View style={styles.actions}>
|
||||||
|
<TouchableOpacity onPress={onClose} style={styles.cancelBtn}>
|
||||||
|
<Text style={{ color: '#666' }}>Cancel</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={async () => {
|
||||||
|
const domain = port ? `${host}:${port}` : host;
|
||||||
|
await saveServerDomain(domain, port === '443');
|
||||||
|
onClose();
|
||||||
|
Alert.alert('Saved', 'Restart app to take effect');
|
||||||
|
}}
|
||||||
|
style={styles.saveBtn}
|
||||||
|
>
|
||||||
|
<Text style={{ color: '#fff', fontWeight: 'bold' }}>Save</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
box: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderRadius: 10,
|
||||||
|
padding: 20,
|
||||||
|
width: '85%',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
marginBottom: 12,
|
||||||
|
},
|
||||||
|
presets: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 6,
|
||||||
|
marginBottom: 14,
|
||||||
|
},
|
||||||
|
presetBtn: {
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 5,
|
||||||
|
borderRadius: 6,
|
||||||
|
backgroundColor: '#f0f0f0',
|
||||||
|
},
|
||||||
|
presetBtnActive: { backgroundColor: '#3498db' },
|
||||||
|
inputLabel: {
|
||||||
|
fontSize: 13,
|
||||||
|
color: '#666',
|
||||||
|
marginBottom: 4,
|
||||||
|
},
|
||||||
|
textInput: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#ddd',
|
||||||
|
borderRadius: 6,
|
||||||
|
paddingHorizontal: 10,
|
||||||
|
paddingVertical: 8,
|
||||||
|
marginBottom: 12,
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
},
|
||||||
|
cancelBtn: {
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 8,
|
||||||
|
marginRight: 10,
|
||||||
|
},
|
||||||
|
saveBtn: {
|
||||||
|
backgroundColor: '#3498db',
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
paddingVertical: 8,
|
||||||
|
borderRadius: 6,
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -51,12 +51,17 @@ import {
|
|||||||
AmazonPayOTPBind,
|
AmazonPayOTPBind,
|
||||||
} from '../components/WalletBindComponents';
|
} from '../components/WalletBindComponents';
|
||||||
import { WalletSelectModal, WALLET_ICONS, WALLET_TYPE_COLORS } from '../components/WalletSelectModal';
|
import { WalletSelectModal, WALLET_ICONS, WALLET_TYPE_COLORS } from '../components/WalletSelectModal';
|
||||||
|
import { ServerSettingsModal } from '../components/ServerSettingsModal';
|
||||||
|
|
||||||
import Api, {
|
import Api, {
|
||||||
WalletItem,
|
WalletItem,
|
||||||
loadServerDomain,
|
loadServerDomain,
|
||||||
saveServerDomain,
|
|
||||||
getServerDomain,
|
getServerDomain,
|
||||||
|
getTokenAutoRebindEnabled,
|
||||||
|
getTokenAutoRebindDebug,
|
||||||
|
getTokenAutoRebindOptions,
|
||||||
|
saveTokenAutoRebindEnabled,
|
||||||
|
saveTokenAutoRebindDebug,
|
||||||
} from '../services/api';
|
} from '../services/api';
|
||||||
|
|
||||||
function formatWalletTypeLabel(walletType: string) {
|
function formatWalletTypeLabel(walletType: string) {
|
||||||
@@ -124,6 +129,8 @@ interface HomeScreenState {
|
|||||||
// proxy
|
// proxy
|
||||||
proxyStatus: 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
|
proxyStatus: 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
|
||||||
proxyError?: string;
|
proxyError?: string;
|
||||||
|
tokenAutoRebind: boolean;
|
||||||
|
tokenAutoRebindDebug: boolean;
|
||||||
// server settings
|
// server settings
|
||||||
showServerSettings: boolean;
|
showServerSettings: boolean;
|
||||||
settingsHost: string;
|
settingsHost: string;
|
||||||
@@ -170,6 +177,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
freechargePersonalBindType: 'otpMode',
|
freechargePersonalBindType: 'otpMode',
|
||||||
showAmazonPayPersonalBind: false,
|
showAmazonPayPersonalBind: false,
|
||||||
proxyStatus: 'idle',
|
proxyStatus: 'idle',
|
||||||
|
tokenAutoRebind: false,
|
||||||
|
tokenAutoRebindDebug: false,
|
||||||
showServerSettings: false,
|
showServerSettings: false,
|
||||||
settingsHost: '',
|
settingsHost: '',
|
||||||
settingsPort: '',
|
settingsPort: '',
|
||||||
@@ -190,6 +199,11 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
await loadServerDomain();
|
await loadServerDomain();
|
||||||
|
const tokenAutoRebind = getTokenAutoRebindEnabled();
|
||||||
|
const tokenAutoRebindDebug = getTokenAutoRebindDebug();
|
||||||
|
this.setState({ tokenAutoRebind, tokenAutoRebindDebug });
|
||||||
|
proxyBackgroundService.setTokenAutoRebindEnabled(tokenAutoRebind);
|
||||||
|
proxyBackgroundService.setTokenAutoRebindDebugLog(tokenAutoRebindDebug);
|
||||||
await this.setupPermissions();
|
await this.setupPermissions();
|
||||||
|
|
||||||
const doLogin = () => {
|
const doLogin = () => {
|
||||||
@@ -229,6 +243,19 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
this.clientId = DeviceInfo.getUniqueIdSync();
|
this.clientId = DeviceInfo.getUniqueIdSync();
|
||||||
const userId = Api.instance.getUserId();
|
const userId = Api.instance.getUserId();
|
||||||
this.setState({ proxyStatus: 'connecting' });
|
this.setState({ proxyStatus: 'connecting' });
|
||||||
|
proxyBackgroundService.configureTokenAutoRebind(
|
||||||
|
{
|
||||||
|
listWallets: () => Api.instance.listWallets(),
|
||||||
|
register: (walletType: WalletType, params: Record<string, unknown>) =>
|
||||||
|
Api.instance.register(walletType, params),
|
||||||
|
getUserToken: () => Api.instance.getUserToken(),
|
||||||
|
onRebound: () => this.fetchWallets(),
|
||||||
|
isTokenMode: async (w) => w.otpMode !== true,
|
||||||
|
},
|
||||||
|
getTokenAutoRebindOptions(),
|
||||||
|
);
|
||||||
|
proxyBackgroundService.setTokenAutoRebindEnabled(this.state.tokenAutoRebind);
|
||||||
|
proxyBackgroundService.setTokenAutoRebindDebugLog(this.state.tokenAutoRebindDebug);
|
||||||
await proxyBackgroundService.start({
|
await proxyBackgroundService.start({
|
||||||
wsUrl: Api.WS_URL, clientId: this.clientId || '', userId,
|
wsUrl: Api.WS_URL, clientId: this.clientId || '', userId,
|
||||||
debug: true, heartbeatInterval: 10000, reconnectInterval: 5000, reconnectMaxAttempts: Infinity,
|
debug: true, heartbeatInterval: 10000, reconnectInterval: 5000, reconnectMaxAttempts: Infinity,
|
||||||
@@ -243,12 +270,25 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
|
|
||||||
stopProxyClient() {
|
stopProxyClient() {
|
||||||
try {
|
try {
|
||||||
|
proxyBackgroundService.configureTokenAutoRebind(null);
|
||||||
proxyBackgroundService.stop();
|
proxyBackgroundService.stop();
|
||||||
} catch {
|
} catch {
|
||||||
/* ignore */
|
/* ignore */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleTokenAutoRebind = async (enabled: boolean) => {
|
||||||
|
this.setState({ tokenAutoRebind: enabled });
|
||||||
|
await saveTokenAutoRebindEnabled(enabled);
|
||||||
|
proxyBackgroundService.setTokenAutoRebindEnabled(enabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleTokenAutoRebindDebug = async (enabled: boolean) => {
|
||||||
|
this.setState({ tokenAutoRebindDebug: enabled });
|
||||||
|
await saveTokenAutoRebindDebug(enabled);
|
||||||
|
proxyBackgroundService.setTokenAutoRebindDebugLog(enabled);
|
||||||
|
};
|
||||||
|
|
||||||
/** OTP / bind:API catch → { success:false, message } */
|
/** OTP / bind:API catch → { success:false, message } */
|
||||||
private wrapOtpCall = async (fn: () => Promise<any>): Promise<any> => {
|
private wrapOtpCall = async (fn: () => Promise<any>): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
@@ -783,76 +823,6 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
renderServerSettingsModal() {
|
|
||||||
const { showServerSettings, settingsHost, settingsPort } = this.state;
|
|
||||||
const presets = [
|
|
||||||
{ label: 'aa.pfgame.org', host: 'aa.pfgame.org', port: '443' },
|
|
||||||
{ label: '192.168.1.117:16000', host: '192.168.1.117', port: '16000' },
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
visible={showServerSettings}
|
|
||||||
transparent
|
|
||||||
animationType="fade"
|
|
||||||
>
|
|
||||||
<View style={s.modalOverlay}>
|
|
||||||
<View style={s.settingsBox}>
|
|
||||||
<Text style={s.settingsTitle}>Server Settings</Text>
|
|
||||||
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 6, marginBottom: 14 }}>
|
|
||||||
{presets.map((p) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={p.label}
|
|
||||||
onPress={() => this.setState({ settingsHost: p.host, settingsPort: p.port })}
|
|
||||||
style={[s.presetBtn, settingsHost === p.host && settingsPort === p.port && s.presetBtnActive]}
|
|
||||||
>
|
|
||||||
<Text style={{ fontSize: 12, color: settingsHost === p.host && settingsPort === p.port ? '#fff' : '#333' }}>
|
|
||||||
{p.label}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
<Text style={s.inputLabel}>Host</Text>
|
|
||||||
<TextInput
|
|
||||||
style={s.textInput}
|
|
||||||
value={settingsHost}
|
|
||||||
onChangeText={(t) => this.setState({ settingsHost: t })}
|
|
||||||
placeholder="192.168.1.198"
|
|
||||||
autoCapitalize="none"
|
|
||||||
/>
|
|
||||||
<Text style={s.inputLabel}>Port</Text>
|
|
||||||
<TextInput
|
|
||||||
style={[s.textInput, { marginBottom: 20 }]}
|
|
||||||
value={settingsPort}
|
|
||||||
onChangeText={(t) => this.setState({ settingsPort: t })}
|
|
||||||
placeholder="16000"
|
|
||||||
keyboardType="number-pad"
|
|
||||||
/>
|
|
||||||
<View style={{ flexDirection: 'row', justifyContent: 'flex-end' }}>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => this.setState({ showServerSettings: false })}
|
|
||||||
style={{ paddingHorizontal: 16, paddingVertical: 8, marginRight: 10 }}
|
|
||||||
>
|
|
||||||
<Text style={{ color: '#666' }}>Cancel</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={async () => {
|
|
||||||
const { settingsHost, settingsPort } = this.state;
|
|
||||||
const domain = settingsPort ? `${settingsHost}:${settingsPort}` : settingsHost;
|
|
||||||
await saveServerDomain(domain, settingsPort === '443');
|
|
||||||
this.setState({ showServerSettings: false });
|
|
||||||
Alert.alert('Saved', 'Restart app to take effect');
|
|
||||||
}}
|
|
||||||
style={s.saveBtn}
|
|
||||||
>
|
|
||||||
<Text style={{ color: '#fff', fontWeight: 'bold' }}>Save</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderWalletItem = (item: WalletItem) => {
|
renderWalletItem = (item: WalletItem) => {
|
||||||
const color = WALLET_TYPE_COLORS[item.walletType] ?? '#888';
|
const color = WALLET_TYPE_COLORS[item.walletType] ?? '#888';
|
||||||
const isActive = item.status === 'ACTIVE';
|
const isActive = item.status === 'ACTIVE';
|
||||||
@@ -1032,16 +1002,37 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
error: { label: 'Error', color: '#e74c3c' },
|
error: { label: 'Error', color: '#e74c3c' },
|
||||||
};
|
};
|
||||||
const { label, color } = proxyCfg[proxyStatus];
|
const { label, color } = proxyCfg[proxyStatus];
|
||||||
|
const { tokenAutoRebind, tokenAutoRebindDebug } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={s.container}>
|
<View style={s.container}>
|
||||||
{/* top bar */}
|
{/* top bar */}
|
||||||
<View style={s.topBar}>
|
<View style={s.topBar}>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flex: 1 }}>
|
||||||
<View style={{ width: 8, height: 8, borderRadius: 4, backgroundColor: color, marginRight: 6 }} />
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<Text style={{ color, fontSize: 13 }}>
|
<View style={{ width: 8, height: 8, borderRadius: 4, backgroundColor: color, marginRight: 6 }} />
|
||||||
Proxy {label}{proxyStatus === 'error' && proxyError ? `: ${proxyError}` : ''}
|
<Text style={{ color, fontSize: 13 }}>
|
||||||
</Text>
|
Proxy {label}{proxyStatus === 'error' && proxyError ? `: ${proxyError}` : ''}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={s.autoRebindRow}>
|
||||||
|
<Text style={s.autoRebindLabel}>Token 失效自动重绑</Text>
|
||||||
|
<Switch
|
||||||
|
value={tokenAutoRebind}
|
||||||
|
onValueChange={this.toggleTokenAutoRebind}
|
||||||
|
trackColor={{ false: '#ddd', true: '#3498db80' }}
|
||||||
|
thumbColor={tokenAutoRebind ? '#3498db' : '#999'}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={s.autoRebindRow}>
|
||||||
|
<Text style={s.autoRebindLabel}>重绑调试日志</Text>
|
||||||
|
<Switch
|
||||||
|
value={tokenAutoRebindDebug}
|
||||||
|
onValueChange={this.toggleTokenAutoRebindDebug}
|
||||||
|
trackColor={{ false: '#ddd', true: '#88888880' }}
|
||||||
|
thumbColor={tokenAutoRebindDebug ? '#666' : '#999'}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@@ -1077,7 +1068,14 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
|
|||||||
{this.renderBoundWalletList()}
|
{this.renderBoundWalletList()}
|
||||||
|
|
||||||
{this.renderBindModal()}
|
{this.renderBindModal()}
|
||||||
{this.renderServerSettingsModal()}
|
<ServerSettingsModal
|
||||||
|
visible={this.state.showServerSettings}
|
||||||
|
host={this.state.settingsHost}
|
||||||
|
port={this.state.settingsPort}
|
||||||
|
onHostChange={(settingsHost) => this.setState({ settingsHost })}
|
||||||
|
onPortChange={(settingsPort) => this.setState({ settingsPort })}
|
||||||
|
onClose={() => this.setState({ showServerSettings: false })}
|
||||||
|
/>
|
||||||
<WalletSelectModal
|
<WalletSelectModal
|
||||||
visible={this.state.showAddWallet}
|
visible={this.state.showAddWallet}
|
||||||
onClose={() => this.setState({ showAddWallet: false })}
|
onClose={() => this.setState({ showAddWallet: false })}
|
||||||
@@ -1104,6 +1102,16 @@ const s = StyleSheet.create({
|
|||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: '#e0e0e0',
|
borderBottomColor: '#e0e0e0',
|
||||||
},
|
},
|
||||||
|
autoRebindRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: 6,
|
||||||
|
gap: 8,
|
||||||
|
},
|
||||||
|
autoRebindLabel: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#666',
|
||||||
|
},
|
||||||
addBtn: {
|
addBtn: {
|
||||||
backgroundColor: '#3498db',
|
backgroundColor: '#3498db',
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
@@ -1321,44 +1329,6 @@ const s = StyleSheet.create({
|
|||||||
width: 16,
|
width: 16,
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
},
|
},
|
||||||
settingsBox: {
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
borderRadius: 10,
|
|
||||||
padding: 20,
|
|
||||||
width: '85%',
|
|
||||||
},
|
|
||||||
settingsTitle: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
marginBottom: 12,
|
|
||||||
},
|
|
||||||
presetBtn: {
|
|
||||||
paddingHorizontal: 10,
|
|
||||||
paddingVertical: 5,
|
|
||||||
borderRadius: 6,
|
|
||||||
backgroundColor: '#f0f0f0',
|
|
||||||
},
|
|
||||||
presetBtnActive: { backgroundColor: '#3498db' },
|
|
||||||
inputLabel: {
|
|
||||||
fontSize: 13,
|
|
||||||
color: '#666',
|
|
||||||
marginBottom: 4,
|
|
||||||
},
|
|
||||||
textInput: {
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: '#ddd',
|
|
||||||
borderRadius: 6,
|
|
||||||
paddingHorizontal: 10,
|
|
||||||
paddingVertical: 8,
|
|
||||||
marginBottom: 12,
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
saveBtn: {
|
|
||||||
backgroundColor: '#3498db',
|
|
||||||
paddingHorizontal: 16,
|
|
||||||
paddingVertical: 8,
|
|
||||||
borderRadius: 6,
|
|
||||||
},
|
|
||||||
otpBar: {
|
otpBar: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
|||||||
@@ -13,6 +13,24 @@ export interface WalletItem {
|
|||||||
const DEFAULT_DOMAIN = 'aa.pfgame.org';
|
const DEFAULT_DOMAIN = 'aa.pfgame.org';
|
||||||
const STORAGE_KEY = 'server_domain';
|
const STORAGE_KEY = 'server_domain';
|
||||||
const HTTPS_KEY = 'server_https';
|
const HTTPS_KEY = 'server_https';
|
||||||
|
const TOKEN_AUTO_REBIND_KEY = 'token_auto_rebind_enabled';
|
||||||
|
const TOKEN_AUTO_REBIND_SCAN_MS_KEY = 'token_auto_rebind_scan_ms';
|
||||||
|
const TOKEN_AUTO_REBIND_COOLDOWN_MS_KEY = 'token_auto_rebind_cooldown_ms';
|
||||||
|
const TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS_KEY = 'token_auto_rebind_fail_cooldown_ms';
|
||||||
|
const TOKEN_AUTO_REBIND_DEBUG_KEY = 'token_auto_rebind_debug';
|
||||||
|
|
||||||
|
/** 扫 list 间隔 */
|
||||||
|
const DEFAULT_TOKEN_AUTO_REBIND_SCAN_MS = 1 * 60 * 1000;
|
||||||
|
/** 重绑成功后冷却 */
|
||||||
|
const DEFAULT_TOKEN_AUTO_REBIND_COOLDOWN_MS = 1 * 60 * 1000;
|
||||||
|
/** 重绑失败后冷却 */
|
||||||
|
const DEFAULT_TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS = 1 * 60 * 1000;
|
||||||
|
|
||||||
|
let _tokenAutoRebindEnabled = false;
|
||||||
|
let _tokenAutoRebindDebug = false;
|
||||||
|
let _tokenAutoRebindScanMs = DEFAULT_TOKEN_AUTO_REBIND_SCAN_MS;
|
||||||
|
let _tokenAutoRebindCooldownMs = DEFAULT_TOKEN_AUTO_REBIND_COOLDOWN_MS;
|
||||||
|
let _tokenAutoRebindFailCooldownMs = DEFAULT_TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS;
|
||||||
|
|
||||||
let _domain = DEFAULT_DOMAIN;
|
let _domain = DEFAULT_DOMAIN;
|
||||||
let _useHttps = true;
|
let _useHttps = true;
|
||||||
@@ -22,10 +40,74 @@ export async function loadServerDomain(): Promise<string> {
|
|||||||
if (saved) _domain = saved;
|
if (saved) _domain = saved;
|
||||||
const https = await AsyncStorage.getItem(HTTPS_KEY);
|
const https = await AsyncStorage.getItem(HTTPS_KEY);
|
||||||
if (https !== null) _useHttps = https === 'true';
|
if (https !== null) _useHttps = https === 'true';
|
||||||
|
const autoRebind = await AsyncStorage.getItem(TOKEN_AUTO_REBIND_KEY);
|
||||||
|
_tokenAutoRebindEnabled = autoRebind === 'true';
|
||||||
|
const scanMs = await AsyncStorage.getItem(TOKEN_AUTO_REBIND_SCAN_MS_KEY);
|
||||||
|
const cooldownMs = await AsyncStorage.getItem(TOKEN_AUTO_REBIND_COOLDOWN_MS_KEY);
|
||||||
|
if (scanMs) {
|
||||||
|
const n = parseInt(scanMs, 10);
|
||||||
|
if (Number.isFinite(n) && n > 0) _tokenAutoRebindScanMs = n;
|
||||||
|
}
|
||||||
|
if (cooldownMs) {
|
||||||
|
const n = parseInt(cooldownMs, 10);
|
||||||
|
if (Number.isFinite(n) && n > 0) _tokenAutoRebindCooldownMs = n;
|
||||||
|
}
|
||||||
|
const failCooldownMs = await AsyncStorage.getItem(TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS_KEY);
|
||||||
|
if (failCooldownMs) {
|
||||||
|
const n = parseInt(failCooldownMs, 10);
|
||||||
|
if (Number.isFinite(n) && n > 0) _tokenAutoRebindFailCooldownMs = n;
|
||||||
|
}
|
||||||
|
const debug = await AsyncStorage.getItem(TOKEN_AUTO_REBIND_DEBUG_KEY);
|
||||||
|
_tokenAutoRebindDebug = debug === 'true';
|
||||||
console.log('loadServerDomain', _domain, 'https:', _useHttps);
|
console.log('loadServerDomain', _domain, 'https:', _useHttps);
|
||||||
return _domain;
|
return _domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTokenAutoRebindOptions(): {
|
||||||
|
scanIntervalMs: number;
|
||||||
|
cooldownMs: number;
|
||||||
|
failCooldownMs: number;
|
||||||
|
debugLog: boolean;
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
scanIntervalMs: _tokenAutoRebindScanMs,
|
||||||
|
cooldownMs: _tokenAutoRebindCooldownMs,
|
||||||
|
failCooldownMs: _tokenAutoRebindFailCooldownMs,
|
||||||
|
debugLog: _tokenAutoRebindDebug,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenAutoRebindDebug(): boolean {
|
||||||
|
return _tokenAutoRebindDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveTokenAutoRebindDebug(enabled: boolean): Promise<void> {
|
||||||
|
_tokenAutoRebindDebug = enabled;
|
||||||
|
await AsyncStorage.setItem(TOKEN_AUTO_REBIND_DEBUG_KEY, String(enabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveTokenAutoRebindOptions(
|
||||||
|
scanIntervalMs: number,
|
||||||
|
cooldownMs: number,
|
||||||
|
failCooldownMs: number = DEFAULT_TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS,
|
||||||
|
): Promise<void> {
|
||||||
|
_tokenAutoRebindScanMs = scanIntervalMs;
|
||||||
|
_tokenAutoRebindCooldownMs = cooldownMs;
|
||||||
|
_tokenAutoRebindFailCooldownMs = failCooldownMs;
|
||||||
|
await AsyncStorage.setItem(TOKEN_AUTO_REBIND_SCAN_MS_KEY, String(scanIntervalMs));
|
||||||
|
await AsyncStorage.setItem(TOKEN_AUTO_REBIND_COOLDOWN_MS_KEY, String(cooldownMs));
|
||||||
|
await AsyncStorage.setItem(TOKEN_AUTO_REBIND_FAIL_COOLDOWN_MS_KEY, String(failCooldownMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenAutoRebindEnabled(): boolean {
|
||||||
|
return _tokenAutoRebindEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function saveTokenAutoRebindEnabled(enabled: boolean): Promise<void> {
|
||||||
|
_tokenAutoRebindEnabled = enabled;
|
||||||
|
await AsyncStorage.setItem(TOKEN_AUTO_REBIND_KEY, String(enabled));
|
||||||
|
}
|
||||||
|
|
||||||
export async function saveServerDomain(domain: string, useHttps: boolean): Promise<void> {
|
export async function saveServerDomain(domain: string, useHttps: boolean): Promise<void> {
|
||||||
_domain = domain;
|
_domain = domain;
|
||||||
_useHttps = useHttps;
|
_useHttps = useHttps;
|
||||||
|
|||||||
Reference in New Issue
Block a user