197 lines
6.9 KiB
Dart
197 lines
6.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../../../core/network/api_handler.dart';
|
|
import '../../../../core/utils/validators.dart';
|
|
import '../../../../shared/widgets/app_button.dart';
|
|
import '../../../../shared/widgets/app_text_field.dart';
|
|
import '../../domain/entities/app_settings.dart';
|
|
import '../providers/settings_provider.dart';
|
|
import '../widgets/settings_widgets.dart';
|
|
import '../../../../shared/widgets/app_toast.dart';
|
|
|
|
class EmailConfigurationScreen extends ConsumerStatefulWidget {
|
|
const EmailConfigurationScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<EmailConfigurationScreen> createState() =>
|
|
_EmailConfigurationScreenState();
|
|
}
|
|
|
|
class _EmailConfigurationScreenState
|
|
extends ConsumerState<EmailConfigurationScreen> {
|
|
final _formKey = GlobalKey<FormState>();
|
|
late final TextEditingController _hostController;
|
|
late final TextEditingController _portController;
|
|
late final TextEditingController _usernameController;
|
|
late final TextEditingController _passwordController;
|
|
late final TextEditingController _senderEmailController;
|
|
late final TextEditingController _senderNameController;
|
|
|
|
bool _loading = true;
|
|
bool _saving = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
final email = ref.read(appSettingsProvider).email;
|
|
_hostController = TextEditingController(text: email.smtpHost);
|
|
_portController = TextEditingController(text: '${email.smtpPort}');
|
|
_usernameController = TextEditingController(text: email.smtpUsername);
|
|
_passwordController = TextEditingController(text: email.smtpPassword);
|
|
_senderEmailController = TextEditingController(text: email.senderEmail);
|
|
_senderNameController = TextEditingController(text: email.senderName);
|
|
WidgetsBinding.instance.addPostFrameCallback((_) => _loadFromApi());
|
|
}
|
|
|
|
Future<void> _loadFromApi() async {
|
|
setState(() => _loading = true);
|
|
final failure =
|
|
await ref.read(appSettingsProvider.notifier).refreshEmailSettings();
|
|
if (!mounted) return;
|
|
_applyEmail(ref.read(appSettingsProvider).email);
|
|
setState(() => _loading = false);
|
|
if (failure != null) {
|
|
showAppToastFromSnackBar(context,
|
|
SnackBar(
|
|
content: Text(failure.message),
|
|
backgroundColor: Theme.of(context).colorScheme.error,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
void _applyEmail(EmailConfigurationSettings email) {
|
|
_hostController.text = email.smtpHost;
|
|
_portController.text = '${email.smtpPort}';
|
|
_usernameController.text = email.smtpUsername;
|
|
if (email.smtpPassword.isNotEmpty) {
|
|
_passwordController.text = email.smtpPassword;
|
|
}
|
|
_senderEmailController.text = email.senderEmail;
|
|
_senderNameController.text = email.senderName;
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_hostController.dispose();
|
|
_portController.dispose();
|
|
_usernameController.dispose();
|
|
_passwordController.dispose();
|
|
_senderEmailController.dispose();
|
|
_senderNameController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _save() async {
|
|
if (!_formKey.currentState!.validate()) return;
|
|
|
|
final port = int.tryParse(_portController.text.trim());
|
|
if (port == null || port <= 0) {
|
|
showAppToastFromSnackBar(context,
|
|
const SnackBar(content: Text('Enter a valid SMTP port')),
|
|
);
|
|
return;
|
|
}
|
|
|
|
final current = ref.read(appSettingsProvider).email;
|
|
setState(() => _saving = true);
|
|
final failure = await ref.read(appSettingsProvider.notifier).updateEmail(
|
|
current.copyWith(
|
|
smtpHost: _hostController.text.trim(),
|
|
smtpPort: port,
|
|
smtpUsername: _usernameController.text.trim(),
|
|
smtpPassword: _passwordController.text.trim(),
|
|
senderEmail: _senderEmailController.text.trim(),
|
|
senderName: _senderNameController.text.trim(),
|
|
),
|
|
);
|
|
if (!mounted) return;
|
|
setState(() => _saving = false);
|
|
|
|
if (failure != null) {
|
|
showAppToastFromSnackBar(context,
|
|
SnackBar(
|
|
content: Text(validationErrorMessage(failure)),
|
|
backgroundColor: Theme.of(context).colorScheme.error,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
showAppToastFromSnackBar(context,
|
|
const SnackBar(content: Text('Email configuration saved')),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SettingsPageLayout(
|
|
title: 'Email Configuration',
|
|
subtitle: 'SMTP server settings',
|
|
child: _loading
|
|
? const Padding(
|
|
padding: EdgeInsets.symmetric(vertical: 48),
|
|
child: Center(child: CircularProgressIndicator()),
|
|
)
|
|
: Form(
|
|
key: _formKey,
|
|
child: Column(
|
|
children: [
|
|
SettingsFormCard(
|
|
title: 'SMTP Settings',
|
|
children: [
|
|
AppTextField(
|
|
controller: _hostController,
|
|
label: 'SMTP Host',
|
|
hint: 'smtp.gmail.com',
|
|
validator: (v) =>
|
|
Validators.required(v, fieldName: 'SMTP Host'),
|
|
),
|
|
const SizedBox(height: 16),
|
|
AppTextField(
|
|
controller: _portController,
|
|
label: 'SMTP Port',
|
|
keyboardType: TextInputType.number,
|
|
validator: (v) =>
|
|
Validators.required(v, fieldName: 'SMTP Port'),
|
|
),
|
|
const SizedBox(height: 16),
|
|
AppTextField(
|
|
controller: _usernameController,
|
|
label: 'Username',
|
|
),
|
|
const SizedBox(height: 16),
|
|
AppTextField(
|
|
controller: _passwordController,
|
|
label: 'Password',
|
|
obscureText: true,
|
|
hint: 'Leave blank to keep existing password',
|
|
),
|
|
const SizedBox(height: 16),
|
|
AppTextField(
|
|
controller: _senderEmailController,
|
|
label: 'Sender Email',
|
|
keyboardType: TextInputType.emailAddress,
|
|
validator: Validators.email,
|
|
),
|
|
const SizedBox(height: 16),
|
|
AppTextField(
|
|
controller: _senderNameController,
|
|
label: 'Sender Name',
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 24),
|
|
AppButton(
|
|
label: 'Save Changes',
|
|
onPressed: _save,
|
|
isLoading: _saving,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|