11import 'package:flutter/material.dart' ;
2+ import 'package:flutter/services.dart' ;
23import 'package:flutter_secure_storage/flutter_secure_storage.dart' ;
34import 'package:piwigo_ng/app.dart' ;
45import 'package:piwigo_ng/components/buttons/animated_piwigo_button.dart' ;
@@ -131,7 +132,7 @@ class _LoginFormViewState extends State<LoginFormView> {
131132 }
132133
133134 void _onLogin () async {
134- if (_urlError) return ;
135+ // if (_urlError) return;
135136 App .scaffoldMessengerKey.currentState? .clearSnackBars ();
136137 _btnController.start ();
137138 try {
@@ -143,6 +144,7 @@ class _LoginFormViewState extends State<LoginFormView> {
143144 if (result.data == false || result.error != null ) {
144145 _onLoginError (result);
145146 } else {
147+ TextInput .finishAutofillContext ();
146148 await _onLoginSuccess (result);
147149 }
148150 } on Error catch (e) {
@@ -160,129 +162,137 @@ class _LoginFormViewState extends State<LoginFormView> {
160162
161163 @override
162164 Widget build (BuildContext context) {
163- return Column (
164- crossAxisAlignment: CrossAxisAlignment .stretch,
165- children: [
166- AppField (
167- key: _urlKey,
168- margin: const EdgeInsets .symmetric (vertical: 4.0 ),
169- padding: const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
170- controller: _urlController,
171- onChanged: (value) {
172- bool isError = ! _urlValidator (value);
173- if (_urlError != isError) {
174- _urlError = isError;
175- }
176- setState (() {
177- _url = value;
178- });
179- },
180- textInputAction: TextInputAction .next,
181- prefix: _securedPrefix,
182- hint: 'example.piwigo.com' ,
183- error: _urlError,
184- ),
185- AppField (
186- margin: const EdgeInsets .symmetric (vertical: 4.0 ),
187- padding: const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
188- controller: _usernameController,
189- onChanged: (value) {
190- if (_idError) {
191- _idError = false ;
192- }
193- setState (() {
194- _username = value;
195- });
196- },
197- textInputAction: TextInputAction .next,
198- hint: "username" ,
199- error: _idError,
200- prefix: const Icon (Icons .person),
201- suffix: _username.isNotEmpty
202- ? GestureDetector (
203- behavior: HitTestBehavior .opaque,
204- onTap: () => setState (() {
205- _usernameController.clear ();
206- _username = '' ;
207- }),
208- child: Padding (
209- padding: const EdgeInsets .all (8.0 ),
210- child: Icon (
211- Icons .clear,
212- color: Theme .of (context).colorScheme.secondary,
165+ return AutofillGroup (
166+ child: Column (
167+ crossAxisAlignment: CrossAxisAlignment .stretch,
168+ children: [
169+ AppField (
170+ key: _urlKey,
171+ margin: const EdgeInsets .symmetric (vertical: 4.0 ),
172+ padding:
173+ const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
174+ controller: _urlController,
175+ onChanged: (value) {
176+ bool isError = ! _urlValidator (value);
177+ if (_urlError != isError) {
178+ _urlError = isError;
179+ }
180+ setState (() {
181+ _url = value;
182+ });
183+ },
184+ textInputAction: TextInputAction .next,
185+ autofillHints: [AutofillHints .url],
186+ prefix: _securedPrefix,
187+ hint: 'example.piwigo.com' ,
188+ error: _urlError,
189+ ),
190+ AppField (
191+ margin: const EdgeInsets .symmetric (vertical: 4.0 ),
192+ padding:
193+ const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
194+ controller: _usernameController,
195+ onChanged: (value) {
196+ if (_idError) {
197+ _idError = false ;
198+ }
199+ setState (() {
200+ _username = value;
201+ });
202+ },
203+ textInputAction: TextInputAction .next,
204+ autofillHints: [AutofillHints .username],
205+ hint: appStrings.login_userPlaceholder,
206+ error: _idError,
207+ prefix: const Icon (Icons .person),
208+ suffix: _username.isNotEmpty
209+ ? GestureDetector (
210+ behavior: HitTestBehavior .opaque,
211+ onTap: () => setState (() {
212+ _usernameController.clear ();
213+ _username = '' ;
214+ }),
215+ child: Padding (
216+ padding: const EdgeInsets .all (8.0 ),
217+ child: Icon (
218+ Icons .clear,
219+ color: Theme .of (context).colorScheme.secondary,
220+ ),
213221 ),
214- ),
215- )
216- : null ,
217- ),
218- AppField (
219- margin: const EdgeInsets .symmetric (vertical: 4.0 ),
220- padding: const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
221- controller: _passwordController,
222- onFieldSubmitted: (String value) {
223- FocusScope .of (context).unfocus ();
224- _onLogin ();
225- },
226- onChanged: (value) {
227- if (_idError) {
228- _idError = false ;
229- }
230- setState (() {
231- _password = value;
232- });
233- },
234- textInputAction: TextInputAction .done,
235- obscureText: ! _showPassword,
236- hint: "password" ,
237- error: _idError,
238- prefix: GestureDetector (
239- onTap: () => setState (() {
240- _showPassword = ! _showPassword;
241- }),
242- child: Icon (_showPassword ? Icons .lock_open : Icons .lock),
222+ )
223+ : null ,
243224 ),
244- suffix: _password.isNotEmpty
245- ? GestureDetector (
246- behavior: HitTestBehavior .opaque,
247- onTap: () => setState (() {
248- _passwordController.clear ();
249- _password = '' ;
250- }),
251- child: Padding (
252- padding: const EdgeInsets .all (8.0 ),
253- child: Icon (
254- Icons .clear,
255- color: Theme .of (context).colorScheme.secondary,
225+ AppField (
226+ margin: const EdgeInsets .symmetric (vertical: 4.0 ),
227+ padding:
228+ const EdgeInsets .symmetric (vertical: 16.0 , horizontal: 8.0 ),
229+ controller: _passwordController,
230+ onFieldSubmitted: (String value) {
231+ FocusScope .of (context).unfocus ();
232+ _onLogin ();
233+ },
234+ onChanged: (value) {
235+ if (_idError) {
236+ _idError = false ;
237+ }
238+ setState (() {
239+ _password = value;
240+ });
241+ },
242+ textInputAction: TextInputAction .done,
243+ autofillHints: [AutofillHints .password],
244+ obscureText: ! _showPassword,
245+ hint: appStrings.login_passwordPlaceholder,
246+ error: _idError,
247+ prefix: GestureDetector (
248+ onTap: () => setState (() {
249+ _showPassword = ! _showPassword;
250+ }),
251+ child: Icon (_showPassword ? Icons .lock_open : Icons .lock),
252+ ),
253+ suffix: _password.isNotEmpty
254+ ? GestureDetector (
255+ behavior: HitTestBehavior .opaque,
256+ onTap: () => setState (() {
257+ _passwordController.clear ();
258+ _password = '' ;
259+ }),
260+ child: Padding (
261+ padding: const EdgeInsets .all (8.0 ),
262+ child: Icon (
263+ Icons .clear,
264+ color: Theme .of (context).colorScheme.secondary,
265+ ),
256266 ),
257- ),
258- )
259- : null ,
260- ),
261- Padding (
262- padding : const EdgeInsets . only (top : 12.0 ),
263- child : AnimatedPiwigoButton (
264- controller : _btnController ,
265- // disabled: _urlError ,
266- color : Theme . of (context).primaryColor ,
267- onPressed : _onLogin,
268- child : Text (
269- appStrings.login ,
270- style : Theme . of (context).textTheme.displaySmall ,
267+ )
268+ : null ,
269+ ) ,
270+ Padding (
271+ padding : const EdgeInsets . only (top : 12.0 ),
272+ child : AnimatedPiwigoButton (
273+ controller : _btnController,
274+ // disabled: _urlError ,
275+ color : Theme . of (context).primaryColor ,
276+ onPressed : _onLogin ,
277+ child : Text (
278+ appStrings.login,
279+ style : Theme . of (context).textTheme.displaySmall ,
280+ ) ,
271281 ),
272282 ),
273- ),
274- TextButton (
275- style : ButtonStyle (
276- foregroundColor : MaterialStateProperty . resolveWith (
277- (states) => Theme . of (context).colorScheme.secondary ,
283+ TextButton (
284+ style : ButtonStyle (
285+ foregroundColor : MaterialStateProperty . resolveWith (
286+ (states) => Theme . of (context).colorScheme.secondary,
287+ ) ,
278288 ),
289+ onPressed: () {
290+ Navigator .of (context).pushNamed (LoginSettingsPage .routeName);
291+ },
292+ child: Text (appStrings.login_advancedParameters),
279293 ),
280- onPressed: () {
281- Navigator .of (context).pushNamed (LoginSettingsPage .routeName);
282- },
283- child: Text (appStrings.login_advancedParameters),
284- ),
285- ],
294+ ],
295+ ),
286296 );
287297 }
288298
0 commit comments