Files
Toolbox/apps/app_zen_box/screens/LoginScreen.tsx
T
yangxiangyuan 6a043687f5 feat(zen-box): 新增云端配置同步功能,完善应用构建与配置
本次提交实现了观空禅音应用的核心云端同步功能,包括:
1.  添加用户登录验证接口与本地存储管理
2.  新增云端配置存储与拉取接口,支持跨设备同步歌单、播放进度等设置
3.  新增登录页面与设置页账号管理模块
4.  更新依赖包版本与安卓、iOS打包配置
5.  优化缓存下载逻辑,修复OSS链接编码问题
6.  新增离线模式支持,自动过滤无缓存歌单
7.  新增歌曲排序偏好本地与云端同步功能
2026-07-11 10:57:02 +08:00

161 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet, ActivityIndicator, Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { theme } from '../theme';
import * as API from '../api';
interface LoginScreenProps {
onLoginSuccess: () => void;
onBack: () => void;
}
export const LoginScreen: React.FC<LoginScreenProps> = ({ onLoginSuccess, onBack }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const handleLogin = async () => {
if (!username.trim() || !password.trim()) {
Alert.alert('提示', '请输入账号和密码');
return;
}
setLoading(true);
try {
const result = await API.login(username.trim(), password);
if (result.ok) {
Alert.alert('登录成功', `欢迎,${result.username}`, [
{ text: '好的', onPress: onLoginSuccess }
]);
} else {
Alert.alert('登录失败', result.error || '账号或密码错误');
}
} catch (error) {
Alert.alert('错误', '登录请求失败,请检查网络');
} finally {
setLoading(false);
}
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<TouchableOpacity onPress={onBack} style={styles.backBtn}>
<Text style={styles.backText}>← 返回</Text>
</TouchableOpacity>
<Text style={styles.title}>观空禅音</Text>
</View>
<View style={styles.form}>
<Text style={styles.label}>账号</Text>
<TextInput
style={styles.input}
value={username}
onChangeText={setUsername}
placeholder="请输入账号"
placeholderTextColor={theme.colors.textSecondary}
autoCapitalize="none"
autoComplete="off"
/>
<Text style={styles.label}>密码</Text>
<TextInput
style={styles.input}
value={password}
onChangeText={setPassword}
placeholder="请输入密码"
placeholderTextColor={theme.colors.textSecondary}
secureTextEntry
autoComplete="off"
/>
<TouchableOpacity
style={[styles.loginBtn, loading && styles.loginBtnDisabled]}
onPress={handleLogin}
disabled={loading}
>
{loading ? (
<ActivityIndicator size="small" color="#fff" />
) : (
<Text style={styles.loginBtnText}>登录</Text>
)}
</TouchableOpacity>
<Text style={styles.hint}>
登录后可同步歌单选择、播放进度等配置到云端,跨设备使用。
</Text>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: theme.colors.background,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
},
backBtn: {
padding: theme.spacing.xs,
},
backText: {
fontSize: 15,
color: theme.colors.primary,
},
title: {
flex: 1,
textAlign: 'center',
fontSize: 18,
fontWeight: '600',
color: theme.colors.text,
marginRight: 40,
},
form: {
paddingHorizontal: theme.spacing.xl,
paddingTop: theme.spacing.xl,
},
label: {
fontSize: 14,
color: theme.colors.textSecondary,
marginBottom: 6,
},
input: {
backgroundColor: theme.colors.surface,
borderRadius: 8,
paddingHorizontal: theme.spacing.md,
paddingVertical: theme.spacing.sm,
fontSize: 16,
color: theme.colors.text,
marginBottom: theme.spacing.md,
borderWidth: 1,
borderColor: theme.colors.border,
},
loginBtn: {
backgroundColor: theme.colors.primary,
borderRadius: 8,
paddingVertical: theme.spacing.sm,
alignItems: 'center',
marginTop: theme.spacing.md,
},
loginBtnDisabled: {
opacity: 0.6,
},
loginBtnText: {
fontSize: 16,
fontWeight: '600',
color: '#fff',
},
hint: {
fontSize: 13,
color: theme.colors.textSecondary,
marginTop: theme.spacing.lg,
textAlign: 'center',
lineHeight: 20,
},
});