vissh/lib/pages/login_page.dart
2025-07-09 15:13:42 +08:00

141 lines
4.7 KiB
Dart

import 'package:flutter/material.dart';
import 'package:dartssh2/dartssh2.dart';
import '../main.dart';
import '../models/credentials.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final TextEditingController _hostController = TextEditingController();
final TextEditingController _usernameController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
bool _isLoading = false;
Future<void> _login() async {
setState(() {
_isLoading = true;
});
try {
final client = SSHClient(
await SSHSocket.connect(_hostController.text, 22),
username: _usernameController.text,
onPasswordRequest: () => _passwordController.text,
);
final credentials = SSHCredentials(
host: _hostController.text,
username: _usernameController.text,
password: _passwordController.text,
);
if (!mounted) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => WindowManager(
sshClient: client,
credentials: credentials,
),
),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Login Failed: $e')),
);
} finally {
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xff0078D4),
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: NetworkImage('https://www.meowdream.cn/background.jpg'),
fit: BoxFit.cover,
),
),
child: Center(
child: Container(
padding: const EdgeInsets.fromLTRB(40, 20, 40, 20),
width: 300,
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.4),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text('登录',
style: TextStyle(color: Colors.white, fontSize: 24)),
const SizedBox(height: 20),
TextField(
controller: _hostController,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
labelText: '地址',
labelStyle: TextStyle(color: Colors.white70),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)),
),
),
const SizedBox(height: 10),
TextField(
controller: _usernameController,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
labelText: '用户名',
labelStyle: TextStyle(color: Colors.white70),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)),
),
),
const SizedBox(height: 10),
TextField(
controller: _passwordController,
obscureText: true,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
labelText: '密码',
labelStyle: TextStyle(color: Colors.white70),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white70)),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)),
),
),
const SizedBox(height: 20),
_isLoading
? const CircularProgressIndicator()
: ElevatedButton.icon(
onPressed: _login,
icon: const Icon(Icons.login),
label: const Text('连接'),
),
],
),
),
),
),
);
}
}