263 lines
8.7 KiB
Dart
263 lines
8.7 KiB
Dart
import 'package:flutter/material.dart';
|
||
import '../services/webdav_service.dart';
|
||
import 'webdav_file_list_page.dart';
|
||
import '../base/base_state.dart';
|
||
|
||
class WebDAVSetupPage extends StatefulWidget {
|
||
const WebDAVSetupPage({super.key});
|
||
|
||
@override
|
||
State<WebDAVSetupPage> createState() => _WebDAVSetupPageState();
|
||
}
|
||
|
||
class _WebDAVSetupPageState extends BaseState<WebDAVSetupPage> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
final _baseUrlController = TextEditingController();
|
||
final _usernameController = TextEditingController();
|
||
final _passwordController = TextEditingController();
|
||
bool _isLoading = false;
|
||
bool _isConnected = false;
|
||
String _statusText = '未连接';
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_loadSavedCredentials();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_baseUrlController.dispose();
|
||
_usernameController.dispose();
|
||
_passwordController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _loadSavedCredentials() async {
|
||
final hasCred = await WebDAVService.instance.loadCredentials();
|
||
safeSetState(() {
|
||
_isConnected = hasCred;
|
||
_statusText = hasCred ? '已连接' : '未连接';
|
||
if (hasCred) {
|
||
_baseUrlController.text = WebDAVService.instance.baseUrl ?? '';
|
||
}
|
||
});
|
||
}
|
||
|
||
Future<void> _connect() async {
|
||
if (!_formKey.currentState!.validate()) return;
|
||
|
||
safeSetState(() => _isLoading = true);
|
||
|
||
try {
|
||
await WebDAVService.instance.saveCredentials(
|
||
_baseUrlController.text.trim(),
|
||
_usernameController.text.trim(),
|
||
_passwordController.text.trim(),
|
||
);
|
||
|
||
// 验证连接
|
||
await WebDAVService.instance.getMusicFiles();
|
||
|
||
safeSetState(() {
|
||
_isConnected = true;
|
||
_statusText = '已连接';
|
||
_isLoading = false;
|
||
});
|
||
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('✅ WebDAV 连接成功'),
|
||
backgroundColor: Color(0xFF4CAF50),
|
||
),
|
||
);
|
||
// ⭐ 用 pushReplacement 替换当前页面(WebDAVSetupPage)
|
||
// 此时栈底是 HomePage,替换后栈变为 [HomePage, WebDAVFileListPage]
|
||
Navigator.pushReplacement(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (_) => const WebDAVFileListPage(),
|
||
),
|
||
);
|
||
}
|
||
} catch (e) {
|
||
safeSetState(() {
|
||
_isConnected = false;
|
||
_statusText = '连接失败';
|
||
_isLoading = false;
|
||
});
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
SnackBar(
|
||
content: Text('❌ 连接失败: $e'),
|
||
backgroundColor: Colors.red,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
Future<void> _disconnect() async {
|
||
await WebDAVService.instance.clearCredentials();
|
||
safeSetState(() {
|
||
_isConnected = false;
|
||
_statusText = '未连接';
|
||
});
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('已断开连接'),
|
||
backgroundColor: Colors.grey,
|
||
),
|
||
);
|
||
Navigator.pop(context);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: const Color(0xFF0E1211),
|
||
appBar: AppBar(
|
||
title: const Text('WebDAV 设置'),
|
||
backgroundColor: Colors.transparent,
|
||
elevation: 0,
|
||
foregroundColor: Colors.white,
|
||
leading: IconButton(
|
||
icon: const Icon(Icons.arrow_back_ios_new),
|
||
onPressed: () => Navigator.pop(context),
|
||
),
|
||
),
|
||
body: Padding(
|
||
padding: const EdgeInsets.all(24),
|
||
child: Form(
|
||
key: _formKey,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// 状态显示
|
||
Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: const Color(0xFF1A2A2A),
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
_isConnected ? Icons.cloud_done : Icons.cloud_off,
|
||
color:
|
||
_isConnected ? const Color(0xFF4CAF50) : Colors.grey,
|
||
),
|
||
const SizedBox(width: 12),
|
||
Text(
|
||
'状态: $_statusText',
|
||
style: TextStyle(
|
||
color: _isConnected
|
||
? const Color(0xFF4CAF50)
|
||
: Colors.grey[400],
|
||
),
|
||
),
|
||
const Spacer(),
|
||
if (_isConnected)
|
||
TextButton(
|
||
onPressed: _disconnect,
|
||
style:
|
||
TextButton.styleFrom(foregroundColor: Colors.red),
|
||
child: const Text('断开'),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
|
||
// 表单
|
||
TextFormField(
|
||
controller: _baseUrlController,
|
||
enabled: !_isConnected,
|
||
style: const TextStyle(color: Colors.white),
|
||
decoration: const InputDecoration(
|
||
labelText: 'WebDAV 地址',
|
||
labelStyle: TextStyle(color: Colors.grey),
|
||
hintText: 'https://nas.local/dav/',
|
||
hintStyle: TextStyle(color: Colors.grey),
|
||
enabledBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Colors.grey),
|
||
),
|
||
focusedBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Color(0xFFB8D4D0)),
|
||
),
|
||
),
|
||
validator: (v) =>
|
||
v == null || v.isEmpty ? '请输入 WebDAV 地址' : null,
|
||
),
|
||
const SizedBox(height: 16),
|
||
TextFormField(
|
||
controller: _usernameController,
|
||
enabled: !_isConnected,
|
||
style: const TextStyle(color: Colors.white),
|
||
decoration: const InputDecoration(
|
||
labelText: '用户名',
|
||
labelStyle: TextStyle(color: Colors.grey),
|
||
enabledBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Colors.grey),
|
||
),
|
||
focusedBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Color(0xFFB8D4D0)),
|
||
),
|
||
),
|
||
validator: (v) => v == null || v.isEmpty ? '请输入用户名' : null,
|
||
),
|
||
const SizedBox(height: 16),
|
||
TextFormField(
|
||
controller: _passwordController,
|
||
enabled: !_isConnected,
|
||
obscureText: true,
|
||
style: const TextStyle(color: Colors.white),
|
||
decoration: const InputDecoration(
|
||
labelText: '密码',
|
||
labelStyle: TextStyle(color: Colors.grey),
|
||
enabledBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Colors.grey),
|
||
),
|
||
focusedBorder: UnderlineInputBorder(
|
||
borderSide: BorderSide(color: Color(0xFFB8D4D0)),
|
||
),
|
||
),
|
||
validator: (v) => v == null || v.isEmpty ? '请输入密码' : null,
|
||
),
|
||
const SizedBox(height: 32),
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed:
|
||
_isConnected ? null : (_isLoading ? null : _connect),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: const Color(0xFFB8D4D0),
|
||
foregroundColor: Colors.black87,
|
||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
),
|
||
child: _isLoading
|
||
? const SizedBox(
|
||
height: 20,
|
||
width: 20,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
color: Colors.black87,
|
||
),
|
||
)
|
||
: Text(_isConnected ? '已连接' : '连接'),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|