329 lines
10 KiB
Dart
329 lines
10 KiB
Dart
import 'package:flutter/material.dart';
|
||
import '../constants.dart';
|
||
|
||
class FeedbackScreen extends StatefulWidget {
|
||
const FeedbackScreen({super.key});
|
||
|
||
@override
|
||
State<FeedbackScreen> createState() => _FeedbackScreenState();
|
||
}
|
||
|
||
class _FeedbackScreenState extends State<FeedbackScreen> {
|
||
final TextEditingController _feedbackController = TextEditingController();
|
||
final _formKey = GlobalKey<FormState>();
|
||
bool _isSubmitting = false;
|
||
String? _selectedFeedbackType; // 选中的反馈类型
|
||
|
||
@override
|
||
void dispose() {
|
||
_feedbackController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _submitFeedback() async {
|
||
if (!_formKey.currentState!.validate()) {
|
||
return;
|
||
}
|
||
|
||
setState(() {
|
||
_isSubmitting = true;
|
||
});
|
||
|
||
// 模拟提交反馈(实际应用中这里应该调用API)
|
||
await Future.delayed(const Duration(milliseconds: 500));
|
||
|
||
if (mounted) {
|
||
ScaffoldMessenger.of(context).showSnackBar(
|
||
const SnackBar(
|
||
content: Text('Thank you for your feedback!'),
|
||
duration: Duration(seconds: 1),
|
||
),
|
||
);
|
||
|
||
// 0.8秒后返回上一页
|
||
await Future.delayed(const Duration(milliseconds: 800));
|
||
|
||
if (mounted) {
|
||
Navigator.pop(context);
|
||
}
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: const Text('Feedback')),
|
||
body: Form(
|
||
key: _formKey,
|
||
child: ListView(
|
||
padding: const EdgeInsets.all(24.0),
|
||
children: [
|
||
const SizedBox(height: 20),
|
||
// Header
|
||
Container(
|
||
padding: const EdgeInsets.all(20),
|
||
decoration: BoxDecoration(
|
||
color: kCardBackground,
|
||
borderRadius: kCardBorderRadius,
|
||
),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
const Icon(
|
||
Icons.feedback,
|
||
size: 48,
|
||
color: Colors.blueAccent,
|
||
),
|
||
const SizedBox(height: 16),
|
||
const Text(
|
||
'We\'d love to hear from you!',
|
||
style: TextStyle(
|
||
fontSize: 20,
|
||
fontWeight: FontWeight.bold,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'Your feedback helps us improve AtmoSphere. Please share your thoughts, suggestions, or report any issues.',
|
||
style: TextStyle(
|
||
fontSize: 14,
|
||
color: Colors.white.withOpacity(0.7),
|
||
height: 1.5,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 32),
|
||
// Feedback Type Selection
|
||
Text(
|
||
'Feedback Type',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white.withOpacity(0.9),
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Container(
|
||
padding: const EdgeInsets.all(16),
|
||
decoration: BoxDecoration(
|
||
color: kCardBackground,
|
||
borderRadius: kCardBorderRadius,
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_FeedbackTypeOption(
|
||
icon: Icons.bug_report,
|
||
title: 'Bug Report',
|
||
subtitle: 'Report a problem or issue',
|
||
isSelected: _selectedFeedbackType == 'bug',
|
||
onTap: () {
|
||
setState(() {
|
||
_selectedFeedbackType = 'bug';
|
||
});
|
||
},
|
||
),
|
||
const Divider(color: Colors.white24),
|
||
_FeedbackTypeOption(
|
||
icon: Icons.lightbulb_outline,
|
||
title: 'Feature Request',
|
||
subtitle: 'Suggest a new feature',
|
||
isSelected: _selectedFeedbackType == 'feature',
|
||
onTap: () {
|
||
setState(() {
|
||
_selectedFeedbackType = 'feature';
|
||
});
|
||
},
|
||
),
|
||
const Divider(color: Colors.white24),
|
||
_FeedbackTypeOption(
|
||
icon: Icons.star_outline,
|
||
title: 'General Feedback',
|
||
subtitle: 'Share your thoughts',
|
||
isSelected: _selectedFeedbackType == 'general',
|
||
onTap: () {
|
||
setState(() {
|
||
_selectedFeedbackType = 'general';
|
||
});
|
||
},
|
||
),
|
||
],
|
||
),
|
||
),
|
||
const SizedBox(height: 32),
|
||
// Feedback Text Field
|
||
Text(
|
||
'Your Feedback',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.w600,
|
||
color: Colors.white.withOpacity(0.9),
|
||
),
|
||
),
|
||
const SizedBox(height: 12),
|
||
Container(
|
||
decoration: BoxDecoration(
|
||
color: kCardBackground,
|
||
borderRadius: kCardBorderRadius,
|
||
),
|
||
child: TextFormField(
|
||
controller: _feedbackController,
|
||
maxLines: 8,
|
||
style: const TextStyle(color: Colors.white),
|
||
decoration: InputDecoration(
|
||
hintText: 'Please describe your feedback in detail...',
|
||
hintStyle: TextStyle(color: Colors.white.withOpacity(0.5)),
|
||
border: OutlineInputBorder(
|
||
borderRadius: kCardBorderRadius,
|
||
borderSide: BorderSide.none,
|
||
),
|
||
filled: true,
|
||
fillColor: Colors.transparent,
|
||
contentPadding: const EdgeInsets.all(16),
|
||
),
|
||
validator: (value) {
|
||
if (value == null || value.trim().isEmpty) {
|
||
return 'Please enter your feedback';
|
||
}
|
||
if (value.trim().length < 10) {
|
||
return 'Feedback must be at least 10 characters';
|
||
}
|
||
return null;
|
||
},
|
||
),
|
||
),
|
||
const SizedBox(height: 32),
|
||
// Submit Button
|
||
SizedBox(
|
||
width: double.infinity,
|
||
height: 50,
|
||
child: ElevatedButton(
|
||
onPressed: _isSubmitting ? null : _submitFeedback,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.blueAccent,
|
||
foregroundColor: Colors.white,
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
elevation: 0,
|
||
),
|
||
child: _isSubmitting
|
||
? const SizedBox(
|
||
width: 20,
|
||
height: 20,
|
||
child: CircularProgressIndicator(
|
||
strokeWidth: 2,
|
||
valueColor: AlwaysStoppedAnimation<Color>(
|
||
Colors.white,
|
||
),
|
||
),
|
||
)
|
||
: const Text(
|
||
'Submit Feedback',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 24),
|
||
// Note
|
||
Center(
|
||
child: Text(
|
||
'We typically respond within 24-48 hours',
|
||
style: TextStyle(
|
||
fontSize: 12,
|
||
color: Colors.white.withOpacity(0.5),
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(height: 40),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _FeedbackTypeOption extends StatelessWidget {
|
||
final IconData icon;
|
||
final String title;
|
||
final String subtitle;
|
||
final bool isSelected;
|
||
final VoidCallback onTap;
|
||
|
||
const _FeedbackTypeOption({
|
||
required this.icon,
|
||
required this.title,
|
||
required this.subtitle,
|
||
required this.isSelected,
|
||
required this.onTap,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return InkWell(
|
||
onTap: onTap,
|
||
borderRadius: BorderRadius.circular(8),
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
|
||
decoration: BoxDecoration(
|
||
color: isSelected
|
||
? Colors.blueAccent.withOpacity(0.2)
|
||
: Colors.transparent,
|
||
borderRadius: BorderRadius.circular(8),
|
||
border: isSelected
|
||
? Border.all(color: Colors.blueAccent, width: 1.5)
|
||
: null,
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Icon(
|
||
icon,
|
||
color: isSelected ? Colors.blueAccent : Colors.white70,
|
||
size: 24,
|
||
),
|
||
const SizedBox(width: 16),
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
Text(
|
||
title,
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: isSelected
|
||
? FontWeight.bold
|
||
: FontWeight.w600,
|
||
color: Colors.white,
|
||
),
|
||
),
|
||
const SizedBox(height: 4),
|
||
Text(
|
||
subtitle,
|
||
style: TextStyle(
|
||
fontSize: 12,
|
||
color: Colors.white.withOpacity(0.6),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
if (isSelected)
|
||
const Icon(Icons.check_circle, color: Colors.blueAccent, size: 24)
|
||
else
|
||
Icon(
|
||
Icons.radio_button_unchecked,
|
||
color: Colors.white.withOpacity(0.3),
|
||
size: 24,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|