Never give up

Flutter - When to use Enum(feat. authentication) 본문

Flutter

Flutter - When to use Enum(feat. authentication)

대기만성 개발자 2020. 11. 30. 19:52
반응형

필자가 생각하는 Enum의 사용처는 리펙토링할 때 직관적이게 하는것인거 같습니다

(ex : 하드코딩으로 넘기는 int값이 꼴뵈기 싫을때..?)

 

bool으로 간단히 처리할 수 있는것은 bool을 사용하는게 좋지만

 

예를들어 3개 이상일 때는 어떨까요?

 

앞에 ex 부분에 장난식으로 써놓긴 했지만 실제로 index값에 따른 동작을

 

한번 더 확인해야되는 불편함이 있고 직관적이지 않습니다

 

그래서 회원가입 예제를 통해 알아보겠습니다

 

Main

enum AuthState { Correct, InvalidID, ShortLength, Different }

enum AuthText { ID, Password, Check }

class EnumExample extends StatelessWidget {
  final AuthData _data = AuthData();
  final _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    var scope = FocusScope.of(context);
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text('Enum example')),
      body: InkWell(
        onTap: () {
          if (scope.hasFocus) {
            scope.unfocus();
          }
        },
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 30),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Create new account',
                style: TextStyle(
                    fontSize: 30,
                    fontWeight: FontWeight.bold,
                    shadows: [
                      Shadow(color: Colors.grey[400], offset: Offset(2, 2))
                    ]),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 20),
                child: Card(
                  elevation: 8,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20)),
                  child: ListView.separated(
                    shrinkWrap: true,
                    itemCount: 3,
                    itemBuilder: (context, index) {
                      AuthText text = AuthText.values[index];
                      return ListTile(
                          leading: _getIcon(index),
                          title: TextFieldWidget(data: _data, text: text));
                    },
                    separatorBuilder: (context, index) {
                      return Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 40),
                        child: Divider(thickness: 2),
                      );
                    },
                  ),
                ),
              ),
              ButtonTheme(
                height: 40,
                minWidth: double.infinity,
                child: RaisedButton(
                    elevation: 8,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20)),
                    child: Text('Register',
                        style: TextStyle(color: Colors.white, fontSize: 16)),
                    color: Colors.blue,
                    onPressed: () {
                      switch (_data.getState) {
                        case AuthState.Correct:
                          break;
                        case AuthState.InvalidID:
                          _scaffoldKey.currentState.showSnackBar(SnackBar(
                              content: Text(
                                  'Email address is invalid. Please use right email address.')));
                          return;
                        case AuthState.Different:
                          _scaffoldKey.currentState.showSnackBar(SnackBar(
                              content: Text(
                                  'Password is incorrect. Please try again.')));
                          return;
                        case AuthState.ShortLength:
                          _scaffoldKey.currentState.showSnackBar(SnackBar(
                              content: Text(
                                  'Password is too weak. It should be longer than 6.')));
                          return;
                      }
                    }),
              )
            ],
          ),
        ),
      ),
    );
  }

  Icon _getIcon(int index) {
    switch (index) {
      case 0:
        return Icon(Icons.email_outlined);
      case 1:
        return Icon(Icons.lock);
      case 2:
        return Icon(Icons.fact_check_outlined);
      default:
        return Icon(Icons.device_unknown);
    }
  }
}

 

TextField widget

class TextFieldWidget extends StatefulWidget {
  final AuthData data;
  final AuthText text;

  TextFieldWidget({@required this.data, @required this.text});

  @override
  _TextFieldWidgetState createState() => _TextFieldWidgetState();
}

class _TextFieldWidgetState extends State<TextFieldWidget> {
  TextEditingController _controller = TextEditingController();
  bool _isPassword = true;

  @override
  void initState() {
    super.initState();
    if (widget.text == AuthText.ID) {
      _isPassword = false;
    }
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      controller: _controller,
      keyboardType: _isPassword
          ? TextInputType.visiblePassword
          : TextInputType.emailAddress,
      decoration: InputDecoration(
          border: InputBorder.none,
          hintText: _isPassword
              ? ((widget.text == AuthText.Check)
                  ? 'Check Password'
                  : 'Password')
              : 'Email'),
      obscureText: _isPassword,
      onChanged: (value) {
        switch (widget.text) {
          case AuthText.ID:
            widget.data.setId(value);
            break;
          case AuthText.Password:
            widget.data.setPassword(value);
            break;
          case AuthText.Check:
            widget.data.setCheck(value);
            break;
        }
      },
    );
  }
}

 

Data

class AuthData {
  String _id, _password, _check;

  String get getId => _id;

  get getPassword => _password;

  void setId(String value) {
    _id = value;
  }

  void setPassword(String value) {
    _password = value;
  }

  void setCheck(String value) {
    _check = value;
  }

  get isSame => (_password == _check);

  AuthState get getState {
    if (_password.length < 6) {
      return AuthState.ShortLength;
    } else if (!RegExp(
            r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+@[a-zA-Z0-9]+\.[a-zA-Z]+")
        .hasMatch(_id)) {
      return AuthState.InvalidID;
    }

    if (isSame) {
      return AuthState.Correct;
    } else {
      return AuthState.Different;
    }
  }
}

 

먼저 필자가 사용한 enum은 2가지로 Textfield의 구분동작을 위한 AuthText와

 

Register버튼을 눌렀을 때의 상태를 체크해주는 AuthState를 만들어봤습니다

 

Listtile안에 있는 Textfield부분에서 구분동작을 위해 index에 따른 AuthText값을 할당합니다

 

그러면 onChange가 발생할 때 switch문을 통해 필요한 곳에 값이 전달이 됩니다

 

값을 입력한 후에 register를 누르면 switch문에서 data class에서 설정한 getState값에 따라 출력이 바뀌게 됩니다

 

(email validation같은 경우 stackoverflow.com/questions/16800540/validate-email-address-in-dart에서 그대로 가져와서 사용했습니다)

 

다시한번 정리하자면 비교인자가 2개일 경우에는 bool을 사용하는게 좋고

 

3개 이상일 경우 enum을 사용하면 조금 더 직관적이다 정도로 마무리하면 될거 같습니다

(물론 int, string 등 다른 타입을 사용해도 무방합니다)

 

반응형
Comments