[Flutter] 회원가입과 Provider

2AST_\·2022년 4월 28일
0

Flutter

목록 보기
3/4
post-thumbnail

어플리케이션의 사용자를 식별하기 위해서 회원가입 기능을 넣어야했다. 기존의 구글 로그인은 구현하였지만 이메일 로그인 방식도 구현하는 것이 학교 프로젝트 목표기 때문에 먼저 회원가입을 만들어야 했다. 회원가입을 할 시, 파이어베이스에서는 이메일 인증까지 할 수 있는데 일단은 이 부분은 제외하고 회원가입 시스템을 진행하기로 했다. 회원가입 시스템의 WorkFlow는 아래와 같다.

  1. login페이지에서 회원가입 버튼 클릭 -> 이메일입력 창 전환
  2. 이메일 입력 -> 아이디 중복 체크 -> 프로바이더에 저장 -> Submit
  3. 비밀번호 입력 -> 비밀번호 양식 체크 -> 프로바이더에 저장 -> Submit
  4. 학교 선택 -> 프로바이더에 저장(안해도 되지만) -> 회원가입(Firebase)
  5. popuntil(로그인 페이지까지)

이메일 / 비밀번호 / 학교 선택은 한꺼번에 진행해도 되지만 우선 깔끔하게 각 정보 입력 페이지를 분할해서 진행하였다. 각 페이지에서 입력된 정보를 클래스로 넘겨서 회원가입을 진행해도 되지만 이번에 Provider를 공부하기 위해서 Provider를 사용하여 진행하였다.

이번 글에서는 Provider / 회원가입 / popUntil을 중심으로 살펴보겠다.

1. Provider 생성 및 사용

import 'package:flutter/material.dart';

class UserProvider extends ChangeNotifier {
  String _email = ""; 
  String _password = "";
  String _univ = "";

  String get email => _email;
  String get password => _password;
  String get univ => _univ;

  void set email(String input_email) {
    _email = input_email;
    notifyListeners();
  }

  void set password(String input_password) {
    _password = input_password;
    notifyListeners();
  }

  void set univ(String input_univ) {
    _univ = input_univ;
    notifyListeners();
  }
}

회원가입시 필요한 필수 내역인 이메일, 비밀번호, 대학교를 인스턴스로 설정하고 get/set 메서드를 설정했다. 여기서 주의할 점은 set 메서드는 변경이 일어나므로 notifyListners()를 꼭 호출해주어야 한다.

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (_) => UserProvider(),
        child: MaterialApp(
            title: 'Flutter Demo',
            debugShowCheckedModeBanner: false,
            theme: ThemeData(primarySwatch: Colors.orange),
            routes: {
              '/login': (BuildContext context) => LoginWidget(),
              '/main': (BuildContext context) => MainGridView(),
              '/setUniv': (BuildContext context) => AddInfoWidget(),
              '/enrollPassword': (BuildContext context) =>
                  EnrollPasswordWidget()
            },
            home: LoginWidget()));
  }
}

프로바이더를 생성하는 코드

// 프로바이더 인스턴스 생성
late UserProvider _userProvider;

// 프로바이더 사용
_userProvider = Provider.of<UserProvider>(context);

// set
String email = _userProvider.email;

// get
_userProvider.email = _emailConroller.text;

프로바이더를 실제로 사용하는 코드 예시이다.

2. 회원가입(이메일 인증 생략)

회원가입에서는 기본적으로 이메일, 비밀번호가 필요하다. 부가적으로 사진과 이름을 설정할 수 있지만 이 부분은 랜덤으로 설정해주기로 하였다.

  void _submit() {
    _userProvider.email = _emailConroller.text;
    Navigator.push(context,
        MaterialPageRoute(builder: ((context) => EnrollPasswordWidget())));
  }

  void _checkEmail() async {
 	// 정규표현식
    String pattern =
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
    RegExp regExp = new RegExp(pattern);
	
    // 중복 이메일 검사
    bool duplicate = false;
    try {
      var duplicate_email =
          await _firestore.get().then((QuerySnapshot snapshot) {
        snapshot.docs.forEach((doc) {
          print(doc["email"]);
          if (_emailConroller.text == doc["email"]) {
            duplicate = true;
          }
        });
      });
    } catch (e) {
      print(e);
      duplicate = false;
    }
    if (duplicate) {
      setState(() {
        _errorMsg = "이미 이메일이 존재합니다.";
      });
    } else if (!regExp.hasMatch(_emailConroller.text)) {
      setState(() {
        _errorMsg = "올바르게 이메일을 입력하세요";
      });
    } else {
      setState(() {
        _errorMsg = "";
      });
      _userProvider.email = _emailConroller.text;
      _submit();
    }
  }

현재 해당 코드는 아이디를 입력 하는 부분이며 해당 위젯이 해야되는 일은 다음과 같았다.
1. 중복이메일
2. 올바른 이메일 표현
3. 프로바이더 set

비밀번호는 8자리와 특수문자가 포함되어야 하고 최종적으로 대학교를 선택해주면 회원가입이 완료가 된다.

  void _tapUniv(String univ) async {
    _userProvider.univ = univ;

    String input_email = _userProvider.email.toString();
    String input_password = _userProvider.password.toString();
    String input_univ = _userProvider.univ.toString();

    String uid = "";
    try {
      await FirebaseAuth.instance
          .createUserWithEmailAndPassword(
              email: input_email, password: input_password)
          .then((value) => uid = value.user!.uid);
    } catch (e) {
      print(e);
    } finally {
      await FirebaseFirestore.instance.collection("user").doc(uid).set({
        "email": input_email,
        "sign": "local",
        "uid": uid,
        "name": "익명",
        "photo":
            "https://firebasestorage.googleapis.com/v0/b/djm-project-a2f8b.appspot.com/o/userprofile.png?alt=media&token=d964722c-0b67-4453-a701-fd7985164e85",
        "university": input_univ,
        "review": ""
      });

      Navigator.of(context).popUntil((route) => route.isFirst);
    }
  }

최종적으로 대학교 설정까지 마치고 등록하는 메소드

3. popUntil(첫 페이지로 넘어가기)

popuntil은 플러터에서 특정 페이지까지 앱스택에서 삭제하는 함수이다. 원래는 '/login'까지 pop을 하려 했지만 실행결과는 앱에서 모든 스택이 비워지는 현상이 발견되었다. 설정한 경로를 플러터 내부에서 인식하지 못해 생기는 이슈였으며 해당 이슈는 아래의 코드를 이용하여 해결하였다.

Navigator.of(context).popUntil((route) => route.isFirst);

로그인 위젯이 앱스택의 최하단에 위치하였기 때문에 할 수 있었다.

0개의 댓글