This commit is contained in:
2026-04-28 22:04:24 +08:00
parent 80ee99e564
commit 71c940ab46
156 changed files with 5700 additions and 304 deletions

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../main.dart';
import 'home_screen.dart';
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@@ -10,30 +11,30 @@ class LoginScreen extends StatefulWidget {
class _LoginScreenState extends State<LoginScreen> {
final _serverCtrl = TextEditingController(text: 'http://192.168.1.100:3000');
final _userCtrl = TextEditingController();
final _passCtrl = TextEditingController();
final _tokenCtrl = TextEditingController();
bool _loading = false;
String? _error;
Future<void> _submit(bool register) async {
Future<void> _connect() async {
setState(() { _loading = true; _error = null; });
final url = _serverCtrl.text.trim();
final user = _userCtrl.text.trim();
final pass = _passCtrl.text.trim();
final token = _tokenCtrl.text.trim();
try {
apiService.configure(url, '');
final token = register
? await apiService.register(user, pass)
: await apiService.login(user, pass);
final valid = await apiService.verifyToken(token);
if (!valid) {
setState(() { _error = '令牌无效'; _loading = false; });
return;
}
apiService.configure(url, token);
await settings.setServerUrl(url);
await settings.setToken(token);
await apiService.registerDevice('Android');
if (mounted) {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (_) => const HomeScreen()),
MaterialPageRoute(builder: (_) => HomeScreen()),
);
}
} catch (e) {
@@ -61,55 +62,36 @@ class _LoginScreenState extends State<LoginScreen> {
TextField(
controller: _serverCtrl,
decoration: const InputDecoration(
labelText: 'Server URL',
hintText: 'http://your-server:3000',
labelText: '服务器地址',
hintText: 'http://服务器IP:3000',
prefixIcon: Icon(Icons.dns_outlined),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: _userCtrl,
decoration: const InputDecoration(
labelText: 'Username',
prefixIcon: Icon(Icons.person_outline),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
TextField(
controller: _passCtrl,
controller: _tokenCtrl,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
prefixIcon: Icon(Icons.lock_outline),
labelText: '访问令牌',
prefixIcon: Icon(Icons.key),
border: OutlineInputBorder(),
),
onSubmitted: (_) => _submit(false),
onSubmitted: (_) => _connect(),
),
if (_error != null) ...[
const SizedBox(height: 12),
Text(_error!, style: TextStyle(color: colors.error)),
],
const SizedBox(height: 24),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: _loading ? null : () => _submit(true),
child: const Text('Register'),
),
),
const SizedBox(width: 16),
Expanded(
child: FilledButton(
onPressed: _loading ? null : () => _submit(false),
child: _loading
? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Text('Sign In'),
),
),
],
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: _loading ? null : _connect,
child: _loading
? const SizedBox(height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2))
: const Text('连接'),
),
),
],
),