| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- import 'package:flutter/material.dart';
- import 'package:flutter_riverpod/flutter_riverpod.dart';
- import '../../../providers/auth_provider.dart';
- import '../../../providers/database_provider.dart';
- class InitPage extends ConsumerStatefulWidget {
- const InitPage({super.key});
- @override
- ConsumerState<InitPage> createState() => _InitPageState();
- }
- class _InitPageState extends ConsumerState<InitPage> {
- final _codiceCtrl = TextEditingController();
- final _passwordCtrl = TextEditingController();
- final _ragsocCtrl = TextEditingController();
- final _urlCtrl = TextEditingController();
- final _formKey = GlobalKey<FormState>();
- bool _obscurePassword = true;
- @override
- void initState() {
- super.initState();
- _loadUrl();
- }
- Future<void> _loadUrl() async {
- final url = await ref.read(parametriDaoProvider).read('URL');
- _urlCtrl.text = url ?? 'https://';
- }
- @override
- void dispose() {
- _codiceCtrl.dispose();
- _passwordCtrl.dispose();
- _ragsocCtrl.dispose();
- _urlCtrl.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- final authState = ref.watch(authProvider);
- final theme = Theme.of(context);
- final cs = theme.colorScheme;
- return Scaffold(
- body: Stack(
- children: [
- Positioned(
- top: -MediaQuery.of(context).size.height * 0.08,
- right: -MediaQuery.of(context).size.width * 0.05,
- child: Container(
- width: 320,
- height: 320,
- decoration: BoxDecoration(
- color: cs.secondaryContainer.withValues(alpha: 0.15),
- shape: BoxShape.circle,
- ),
- ),
- ),
- Positioned(
- bottom: -MediaQuery.of(context).size.height * 0.08,
- left: -MediaQuery.of(context).size.width * 0.05,
- child: Container(
- width: 320,
- height: 320,
- decoration: BoxDecoration(
- color: cs.primaryContainer.withValues(alpha: 0.08),
- shape: BoxShape.circle,
- ),
- ),
- ),
- Center(
- child: SingleChildScrollView(
- padding: const EdgeInsets.symmetric(horizontal: 16),
- child: ConstrainedBox(
- constraints: const BoxConstraints(maxWidth: 400),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- const SizedBox(height: 32),
- _buildBrandHeader(theme, cs),
- const SizedBox(height: 32),
- _buildFormCard(authState, theme, cs),
- const SizedBox(height: 32),
- const SizedBox(height: 24),
- ],
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
- Widget _buildBrandHeader(ThemeData theme, ColorScheme cs) {
- return Column(
- children: [
- Container(
- width: 64,
- height: 64,
- decoration: BoxDecoration(
- color: cs.primary,
- borderRadius: BorderRadius.circular(12),
- boxShadow: [
- BoxShadow(
- color: Colors.black.withValues(alpha: 0.15),
- blurRadius: 12,
- offset: const Offset(0, 4),
- ),
- ],
- ),
- child: const Icon(Icons.store, color: Colors.white, size: 40),
- ),
- const SizedBox(height: 16),
- Text(
- 'Benvenuto in PowerAge',
- style: theme.textTheme.headlineLarge?.copyWith(
- color: cs.primary,
- letterSpacing: -0.02,
- ),
- ),
- const SizedBox(height: 8),
- Text(
- 'Configura il tuo account agente per iniziare',
- textAlign: TextAlign.center,
- style: theme.textTheme.bodyMedium?.copyWith(
- color: cs.onSurfaceVariant,
- ),
- ),
- ],
- );
- }
- Widget _buildFormCard(AuthState authState, ThemeData theme, ColorScheme cs) {
- return Container(
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(12),
- border: Border.all(color: cs.outlineVariant),
- boxShadow: [
- BoxShadow(
- color: const Color(0xFF0F172A).withValues(alpha: 0.05),
- blurRadius: 12,
- offset: const Offset(0, 4),
- ),
- ],
- ),
- child: Padding(
- padding: const EdgeInsets.all(24),
- child: Form(
- key: _formKey,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- _buildLabeledField(
- label: 'Codice Agente',
- icon: Icons.badge_outlined,
- controller: _codiceCtrl,
- hintText: 'Inserisci il codice agente',
- validator: (v) =>
- v == null || v.isEmpty ? 'Campo obbligatorio' : null,
- ),
- const SizedBox(height: 16),
- _buildPasswordField(cs),
- const SizedBox(height: 16),
- _buildLabeledField(
- label: 'Ragione Sociale (opzionale)',
- icon: Icons.person_outline,
- controller: _ragsocCtrl,
- hintText: 'Inserisci la ragione sociale',
- ),
- const SizedBox(height: 16),
- _buildLabeledField(
- label: 'URL Backend',
- icon: Icons.link,
- controller: _urlCtrl,
- hintText: 'https://api.powerage.cloud',
- validator: (v) =>
- v == null || v.isEmpty ? 'Campo obbligatorio' : null,
- ),
- const SizedBox(height: 24),
- FilledButton.icon(
- onPressed: authState.isLoading
- ? null
- : () {
- if (_formKey.currentState!.validate()) {
- ref.read(authProvider.notifier).initialize(
- codAgente: _codiceCtrl.text,
- password: _passwordCtrl.text,
- ragioneSociale: _ragsocCtrl.text.isEmpty
- ? null
- : _ragsocCtrl.text,
- url: _urlCtrl.text,
- );
- }
- },
- icon: authState.isLoading
- ? const SizedBox(
- width: 20,
- height: 20,
- child: CircularProgressIndicator(
- strokeWidth: 2,
- color: Colors.white,
- ),
- )
- : const Icon(Icons.arrow_forward),
- label: Text(
- authState.isLoading ? 'Configurazione...' : 'Configura'),
- ),
- if (authState.error != null) ...[
- const SizedBox(height: 16),
- _buildErrorCard(authState.error!, cs),
- ],
- ],
- ),
- ),
- ),
- );
- }
- Widget _buildLabeledField({
- required String label,
- required IconData icon,
- required TextEditingController controller,
- required String hintText,
- String? Function(String?)? validator,
- }) {
- final cs = Theme.of(context).colorScheme;
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- label,
- style: TextStyle(
- fontSize: 12,
- height: 16 / 12,
- fontWeight: FontWeight.w600,
- color: cs.onSurface,
- ),
- ),
- const SizedBox(height: 8),
- TextFormField(
- controller: controller,
- decoration: InputDecoration(
- hintText: hintText,
- prefixIcon: Icon(icon, size: 20),
- ),
- validator: validator,
- ),
- ],
- );
- }
- Widget _buildPasswordField(ColorScheme cs) {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- 'Password',
- style: TextStyle(
- fontSize: 12,
- height: 16 / 12,
- fontWeight: FontWeight.w600,
- color: cs.onSurface,
- ),
- ),
- const SizedBox(height: 8),
- TextFormField(
- controller: _passwordCtrl,
- obscureText: _obscurePassword,
- decoration: InputDecoration(
- hintText: '\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022',
- prefixIcon: const Icon(Icons.lock_outline, size: 20),
- suffixIcon: IconButton(
- icon: Icon(
- _obscurePassword
- ? Icons.visibility_outlined
- : Icons.visibility_off_outlined,
- size: 20,
- ),
- onPressed: () {
- setState(() {
- _obscurePassword = !_obscurePassword;
- });
- },
- ),
- ),
- validator: (v) =>
- v == null || v.isEmpty ? 'Campo obbligatorio' : null,
- ),
- ],
- );
- }
- Widget _buildErrorCard(String error, ColorScheme cs) {
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: cs.errorContainer,
- borderRadius: BorderRadius.circular(8),
- ),
- child: Row(
- children: [
- Icon(Icons.error_outline, color: cs.error, size: 20),
- const SizedBox(width: 8),
- Expanded(
- child: Text(
- error,
- style: TextStyle(color: cs.onErrorContainer, fontSize: 14),
- ),
- ),
- ],
- ),
- );
- }
- }
|