]> git.proxmox.com Git - flutter/proxmox_login_manager.git/blobdiff - lib/proxmox_tfa_form.dart
tree wide: various small lint auto-fixes
[flutter/proxmox_login_manager.git] / lib / proxmox_tfa_form.dart
index 001cc52c226e37dc13b76e92254a180d460572c5..f761462aadfc6adfeefc08011439808f87c78c02 100644 (file)
@@ -3,9 +3,9 @@ import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart';
 import 'package:proxmox_login_manager/proxmox_login_form.dart';
 
 class ProxmoxTfaForm extends StatefulWidget {
-  final ProxmoxApiClient apiClient;
+  final ProxmoxApiClient? apiClient;
 
-  const ProxmoxTfaForm({Key key, this.apiClient}) : super(key: key);
+  const ProxmoxTfaForm({Key? key, this.apiClient}) : super(key: key);
 
   @override
   _ProxmoxTfaFormState createState() => _ProxmoxTfaFormState();
@@ -14,18 +14,31 @@ class ProxmoxTfaForm extends StatefulWidget {
 class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
   final TextEditingController _codeController = TextEditingController();
   bool _isLoading = false;
+  List<String> _tfa_kinds = [];
+  String _selected_tfa_kind = "";
+
+  @override
+  void initState() {
+    super.initState();
+    _tfa_kinds = widget.apiClient!.credentials.tfa!.kinds().toList();
+    _selected_tfa_kind = _tfa_kinds[0];
+  }
+
   @override
   Widget build(BuildContext context) {
     return Theme(
-      data: ThemeData.dark().copyWith(accentColor: Color(0xFFE47225)),
+      data: ThemeData.dark().copyWith(
+          colorScheme: const ColorScheme.dark().copyWith(
+              secondary: ProxmoxColors.orange,
+              onSecondary: ProxmoxColors.supportGrey)),
       child: Scaffold(
-        backgroundColor: Theme.of(context).primaryColor,
+        backgroundColor: ProxmoxColors.supportBlue,
         extendBodyBehindAppBar: true,
         appBar: AppBar(
           elevation: 0.0,
           backgroundColor: Colors.transparent,
           leading: IconButton(
-            icon: Icon(Icons.close),
+            icon: const Icon(Icons.close),
             onPressed: () => Navigator.of(context).pop(),
           ),
         ),
@@ -36,65 +49,99 @@ class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
               child: ConstrainedBox(
                 constraints: BoxConstraints.tightFor(
                     height: MediaQuery.of(context).size.height),
-                child: Padding(
-                  padding: const EdgeInsets.all(8.0),
-                  child: Column(
-                    mainAxisAlignment: MainAxisAlignment.start,
-                    crossAxisAlignment: CrossAxisAlignment.center,
-                    children: <Widget>[
-                      Padding(
-                        padding: const EdgeInsets.fromLTRB(0, 100.0, 0, 30.0),
-                        child: Icon(
-                          Icons.lock,
-                          size: 48,
+                child: SafeArea(
+                  child: Padding(
+                    padding: const EdgeInsets.all(8.0),
+                    child: Column(
+                      mainAxisAlignment: MainAxisAlignment.start,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      children: <Widget>[
+                        const Padding(
+                          padding: EdgeInsets.fromLTRB(0, 100.0, 0, 30.0),
+                          child: Icon(
+                            Icons.lock,
+                            size: 48,
+                          ),
+                        ),
+                        const Text(
+                          'Verify',
+                          style: TextStyle(
+                              fontSize: 36,
+                              color: Colors.white,
+                              fontWeight: FontWeight.bold),
                         ),
-                      ),
-                      Text(
-                        'Verify',
-                        style: TextStyle(
-                            fontSize: 36,
-                            color: Colors.white,
-                            fontWeight: FontWeight.bold),
-                      ),
-                      Text(
-                        'Check your second factor provider',
-                        style: TextStyle(
-                            color: Colors.white38, fontWeight: FontWeight.bold),
-                      ),
-                      Padding(
-                        padding: const EdgeInsets.fromLTRB(0, 50.0, 0, 8.0),
-                        child: Container(
-                          width: 150,
-                          child: TextField(
-                              controller: _codeController,
-                              textAlign: TextAlign.center,
-                              decoration: InputDecoration(labelText: 'Code'),
-                              autofocus: true,
-                              onSubmitted: (value) => _submitTfaCode()),
+                        const Text(
+                          'Check your second factor provider',
+                          style: TextStyle(
+                              color: Colors.white38,
+                              fontWeight: FontWeight.bold),
                         ),
-                      ),
-                      Expanded(
-                        child: Align(
-                          alignment: Alignment.bottomCenter,
+                        Padding(
+                          padding: const EdgeInsets.fromLTRB(0, 50.0, 0, 8.0),
                           child: Container(
-                            width: MediaQuery.of(context).size.width,
-                            child: FlatButton(
-                              onPressed: () => _submitTfaCode(),
-                              color: Color(0xFFE47225),
-                              child: Text('Continue'),
-                              disabledColor: Colors.grey,
+                            width: 175,
+                            child: Column(
+                              children: <Widget>[
+                                DropdownButtonFormField(
+                                  decoration: const InputDecoration(
+                                      labelText: 'Method',
+                                      icon: Icon(Icons.input)),
+                                  items: _tfa_kinds
+                                      .map((e) => DropdownMenuItem(
+                                            value: e,
+                                            child: ListTile(title: Text(e)),
+                                          ))
+                                      .toList(),
+                                  onChanged: (String? value) {
+                                    setState(() {
+                                      _selected_tfa_kind = value!;
+                                    });
+                                  },
+                                  selectedItemBuilder: (context) =>
+                                      _tfa_kinds.map((e) => Text(e)).toList(),
+                                  value: _selected_tfa_kind,
+                                ),
+                                TextField(
+                                    controller: _codeController,
+                                    textAlign: TextAlign.center,
+                                    decoration: const InputDecoration(
+                                        labelText: 'Code',
+                                        icon: Icon(Icons.pin)),
+                                    keyboardType: _selected_tfa_kind == 'totp'
+                                        ? TextInputType.number
+                                        : TextInputType.visiblePassword,
+                                    autofocus: true,
+                                    onSubmitted: (value) => _submitTfaCode()),
+                              ],
                             ),
                           ),
                         ),
-                      ),
-                    ],
+                        Expanded(
+                          child: Align(
+                            alignment: Alignment.bottomCenter,
+                            child: Container(
+                              width: MediaQuery.of(context).size.width,
+                              child: TextButton(
+                                style: TextButton.styleFrom(
+                                  foregroundColor: Colors.white,
+                                  backgroundColor: const Color(0xFFE47225),
+                                  disabledBackgroundColor: Colors.grey,
+                                ),
+                                onPressed: () => _submitTfaCode(),
+                                child: const Text('Continue'),
+                              ),
+                            ),
+                          ),
+                        ),
+                      ],
+                    ),
                   ),
                 ),
               ),
             ),
             if (_isLoading)
-              ProxmoxProgressOverlay(
-                message: 'Verify One-Time password...',
+              const ProxmoxProgressOverlay(
+                message: 'Verifying second-factor...',
               )
           ],
         ),
@@ -107,8 +154,8 @@ class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
       _isLoading = true;
     });
     try {
-      final client =
-          await widget.apiClient.finishTfaChallenge(_codeController.text);
+      final client = await widget.apiClient!
+          .finishTfaChallenge(_selected_tfa_kind, _codeController.text);
       Navigator.of(context).pop(client);
     } on ProxmoxApiException catch (e) {
       showDialog(
@@ -122,15 +169,8 @@ class _ProxmoxTfaFormState extends State<ProxmoxTfaForm> {
       print(trace);
       showDialog(
         context: context,
-        builder: (context) => AlertDialog(
-          title: Text('Connection error'),
-          content: Text('Could not establish connection.'),
-          actions: [
-            FlatButton(
-              onPressed: () => Navigator.of(context).pop(),
-              child: Text('Close'),
-            ),
-          ],
+        builder: (context) => ConnectionErrorDialog(
+          exception: e,
         ),
       );
     }