229 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
import 'dart:async';
 | 
						|
 | 
						|
import 'package:flutter/material.dart';
 | 
						|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
 | 
						|
import '../../common.dart';
 | 
						|
import '../../models/model.dart';
 | 
						|
 | 
						|
void clientClose() {
 | 
						|
  msgBox('', 'Close', 'Are you sure to close the connection?');
 | 
						|
}
 | 
						|
 | 
						|
const SEC1 = Duration(seconds: 1);
 | 
						|
void showSuccess({Duration duration = SEC1}) {
 | 
						|
  SmartDialog.dismiss();
 | 
						|
  showToast(translate("Successful"), duration: SEC1);
 | 
						|
}
 | 
						|
 | 
						|
void showError({Duration duration = SEC1}) {
 | 
						|
  SmartDialog.dismiss();
 | 
						|
  showToast(translate("Error"), duration: SEC1);
 | 
						|
}
 | 
						|
 | 
						|
void updatePasswordDialog() {
 | 
						|
  final p0 = TextEditingController();
 | 
						|
  final p1 = TextEditingController();
 | 
						|
  var validateLength = false;
 | 
						|
  var validateSame = false;
 | 
						|
  DialogManager.show((setState, close) {
 | 
						|
    return CustomAlertDialog(
 | 
						|
      title: Text(translate('Set your own password')),
 | 
						|
      content: Form(
 | 
						|
          autovalidateMode: AutovalidateMode.onUserInteraction,
 | 
						|
          child: Column(mainAxisSize: MainAxisSize.min, children: [
 | 
						|
            TextFormField(
 | 
						|
              autofocus: true,
 | 
						|
              obscureText: true,
 | 
						|
              keyboardType: TextInputType.visiblePassword,
 | 
						|
              decoration: InputDecoration(
 | 
						|
                labelText: translate('Password'),
 | 
						|
              ),
 | 
						|
              controller: p0,
 | 
						|
              validator: (v) {
 | 
						|
                if (v == null) return null;
 | 
						|
                final val = v.trim().length > 5;
 | 
						|
                if (validateLength != val) {
 | 
						|
                  // use delay to make setState success
 | 
						|
                  Future.delayed(Duration(microseconds: 1),
 | 
						|
                      () => setState(() => validateLength = val));
 | 
						|
                }
 | 
						|
                return val
 | 
						|
                    ? null
 | 
						|
                    : translate('Too short, at least 6 characters.');
 | 
						|
              },
 | 
						|
            ),
 | 
						|
            TextFormField(
 | 
						|
              obscureText: true,
 | 
						|
              keyboardType: TextInputType.visiblePassword,
 | 
						|
              decoration: InputDecoration(
 | 
						|
                labelText: translate('Confirmation'),
 | 
						|
              ),
 | 
						|
              controller: p1,
 | 
						|
              validator: (v) {
 | 
						|
                if (v == null) return null;
 | 
						|
                final val = p0.text == v;
 | 
						|
                if (validateSame != val) {
 | 
						|
                  Future.delayed(Duration(microseconds: 1),
 | 
						|
                      () => setState(() => validateSame = val));
 | 
						|
                }
 | 
						|
                return val
 | 
						|
                    ? null
 | 
						|
                    : translate('The confirmation is not identical.');
 | 
						|
              },
 | 
						|
            ),
 | 
						|
          ])),
 | 
						|
      actions: [
 | 
						|
        TextButton(
 | 
						|
          style: flatButtonStyle,
 | 
						|
          onPressed: () {
 | 
						|
            close();
 | 
						|
          },
 | 
						|
          child: Text(translate('Cancel')),
 | 
						|
        ),
 | 
						|
        TextButton(
 | 
						|
          style: flatButtonStyle,
 | 
						|
          onPressed: (validateLength && validateSame)
 | 
						|
              ? () async {
 | 
						|
                  close();
 | 
						|
                  showLoading(translate("Waiting"));
 | 
						|
                  if (await FFI.serverModel.updatePassword(p0.text)) {
 | 
						|
                    showSuccess();
 | 
						|
                  } else {
 | 
						|
                    showError();
 | 
						|
                  }
 | 
						|
                }
 | 
						|
              : null,
 | 
						|
          child: Text(translate('OK')),
 | 
						|
        ),
 | 
						|
      ],
 | 
						|
    );
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
void enterPasswordDialog(String id) {
 | 
						|
  final controller = TextEditingController();
 | 
						|
  var remember = FFI.getByName('remember', id) == 'true';
 | 
						|
  DialogManager.show((setState, close) {
 | 
						|
    return CustomAlertDialog(
 | 
						|
      title: Text(translate('Password Required')),
 | 
						|
      content: Column(mainAxisSize: MainAxisSize.min, children: [
 | 
						|
        PasswordWidget(controller: controller),
 | 
						|
        CheckboxListTile(
 | 
						|
          contentPadding: const EdgeInsets.all(0),
 | 
						|
          dense: true,
 | 
						|
          controlAffinity: ListTileControlAffinity.leading,
 | 
						|
          title: Text(
 | 
						|
            translate('Remember password'),
 | 
						|
          ),
 | 
						|
          value: remember,
 | 
						|
          onChanged: (v) {
 | 
						|
            if (v != null) {
 | 
						|
              setState(() => remember = v);
 | 
						|
            }
 | 
						|
          },
 | 
						|
        ),
 | 
						|
      ]),
 | 
						|
      actions: [
 | 
						|
        TextButton(
 | 
						|
          style: flatButtonStyle,
 | 
						|
          onPressed: () {
 | 
						|
            close();
 | 
						|
            backToHome();
 | 
						|
          },
 | 
						|
          child: Text(translate('Cancel')),
 | 
						|
        ),
 | 
						|
        TextButton(
 | 
						|
          style: flatButtonStyle,
 | 
						|
          onPressed: () {
 | 
						|
            var text = controller.text.trim();
 | 
						|
            if (text == '') return;
 | 
						|
            FFI.login(text, remember);
 | 
						|
            close();
 | 
						|
            showLoading(translate('Logging in...'));
 | 
						|
          },
 | 
						|
          child: Text(translate('OK')),
 | 
						|
        ),
 | 
						|
      ],
 | 
						|
    );
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
void wrongPasswordDialog(String id) {
 | 
						|
  DialogManager.show((setState, close) => CustomAlertDialog(
 | 
						|
          title: Text(translate('Wrong Password')),
 | 
						|
          content: Text(translate('Do you want to enter again?')),
 | 
						|
          actions: [
 | 
						|
            TextButton(
 | 
						|
              style: flatButtonStyle,
 | 
						|
              onPressed: () {
 | 
						|
                close();
 | 
						|
                backToHome();
 | 
						|
              },
 | 
						|
              child: Text(translate('Cancel')),
 | 
						|
            ),
 | 
						|
            TextButton(
 | 
						|
              style: flatButtonStyle,
 | 
						|
              onPressed: () {
 | 
						|
                enterPasswordDialog(id);
 | 
						|
              },
 | 
						|
              child: Text(translate('Retry')),
 | 
						|
            ),
 | 
						|
          ]));
 | 
						|
}
 | 
						|
 | 
						|
class PasswordWidget extends StatefulWidget {
 | 
						|
  PasswordWidget({Key? key, required this.controller}) : super(key: key);
 | 
						|
 | 
						|
  final TextEditingController controller;
 | 
						|
 | 
						|
  @override
 | 
						|
  _PasswordWidgetState createState() => _PasswordWidgetState();
 | 
						|
}
 | 
						|
 | 
						|
class _PasswordWidgetState extends State<PasswordWidget> {
 | 
						|
  bool _passwordVisible = false;
 | 
						|
  final _focusNode = FocusNode();
 | 
						|
 | 
						|
  @override
 | 
						|
  void initState() {
 | 
						|
    super.initState();
 | 
						|
    Timer(Duration(milliseconds: 50), () => _focusNode.requestFocus());
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  void dispose() {
 | 
						|
    _focusNode.unfocus();
 | 
						|
    _focusNode.dispose();
 | 
						|
    super.dispose();
 | 
						|
  }
 | 
						|
 | 
						|
  @override
 | 
						|
  Widget build(BuildContext context) {
 | 
						|
    return TextField(
 | 
						|
      focusNode: _focusNode,
 | 
						|
      controller: widget.controller,
 | 
						|
      obscureText: !_passwordVisible,
 | 
						|
      //This will obscure text dynamically
 | 
						|
      keyboardType: TextInputType.visiblePassword,
 | 
						|
      decoration: InputDecoration(
 | 
						|
        labelText: Translator.call('Password'),
 | 
						|
        hintText: Translator.call('Enter your password'),
 | 
						|
        // Here is key idea
 | 
						|
        suffixIcon: IconButton(
 | 
						|
          icon: Icon(
 | 
						|
            // Based on passwordVisible state choose the icon
 | 
						|
            _passwordVisible ? Icons.visibility : Icons.visibility_off,
 | 
						|
            color: Theme.of(context).primaryColorDark,
 | 
						|
          ),
 | 
						|
          onPressed: () {
 | 
						|
            // Update the state i.e. toogle the state of passwordVisible variable
 | 
						|
            setState(() {
 | 
						|
              _passwordVisible = !_passwordVisible;
 | 
						|
            });
 | 
						|
          },
 | 
						|
        ),
 | 
						|
      ),
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 |