본문 바로가기

Flutter/03 Design Pattern

[Flutter] Design Pattern(2) - Controller with Getx

지난 번에 만든 모델을 사용하는 controller 에 대한 예제 코드입니다.

 

login_user_controller.dart

 

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import 'package:sns_login/src/model/login_user.dart'; // 모델링 패턴 파일

class LoginUserController extends GetxController {

  static LoginUserController get to => Get.find(); // Get.find 사용방법을 줄여주는 선언, 별칭임
  final Rx<LoginUser> _curUser = LoginUser().obs; // 로그인 유저정보 변수

  @override
  void onInit() {
    super.onInit();
  }

// 1. app.dart에서 mappingUserInfo 함수 호출
  void mappingUserInfo(AsyncSnapshot snapshot) async {

    var result = await getUserInfo(snapshot.data.uid);
    if (result > 0){
      print('old customer');
    } else {
      print('new customer');
      _initUserInfo(snapshot);
      await getUserInfo(snapshot.data.uid);
    }
  }

// 로그인 사용자 정보를 접근하는 getter
  LoginUser get curUser => _curUser.value;

// 2. firebase에서 고객정보가 있으면 가져오고 없으면 생성함.
  Future getUserInfo(String uid) async {
// Firebase에서 데이터를 가져오는 샘플1  
//    var result = await FirebaseFirestore.instance
//        .collection('user_info')
//        .get();
//
//    final userList = result.docs.map((user) {
//      return LoginUser.fromJson(user);
//    }).where((user) {
//      return (user.uid == uid);
//    }).toList();
//
//    if (userList.isNotEmpty) {
//      _curUser(userList.first);
//    }
//
//    return userList.length.toInt();

// Firebase에서 데이터를 가져오는 샘플2  
    var result = await FirebaseFirestore.instance
        .collection('user_info')
        .doc(uid)
        .get();

    if(result.exists) {
      final userList = LoginUser.fromJson2(result);
      _curUser(userList);
      print('>>>>' + curUser.email.toString());
      return 1;
    }
    print('>>>>' + curUser.email.toString());
    return 0;

  }

// 신규 고객의 경우, 기본 고객정보를 생성하는 함수
  Future _initUserInfo(AsyncSnapshot snapshot) async {
    var _userInfo = FirebaseFirestore.instance
        .collection('user_info')
        .doc(snapshot.data.uid); // 고객의 uid 정보를 이용해서 키값을 지정함

    var _date = DateTime.now();
    var _nextMonth = DateTime(_date.year, _date.month+1, _date.day).toString().split(' ');

    await _userInfo.set(
      LoginUser(
        datetime: _date.toString(),
        displayName: snapshot.data.displayName,
        email: snapshot.data.email,
        expDate: _nextMonth[0],
        uid: snapshot.data.uid,
        language: '',
        photoURL: snapshot.data.photoURL,
        providerId: snapshot.data.providerData[0].providerId,
        sUid: snapshot.data.providerData[0].uid,
        userType: '',
        validation: false,
        appVersion: '',
        lastLogin: '',
        loginCnt: 0,
      ).initToMap()
    ).then((onValue) {
    });
  }

}

 

1. app.dart에서 mappingUserInfo 함수 호출

void mappingUserInfo(AsyncSnapshot snapshot) 함수를 호출하기 위해서는 app.dart 에 controller를 선언해주고 호출해주면 된다. 함수내에서 getUserInfo 함수를 2회 호출하는 이유는 신규 고객인 경우, 기초 데이터를 생성후 다시 불러와야 하기 때문임.

 

<선언부분>

 

 

<호출부분>

 

 

2. Future getUserInfo(String uid) 호출 - mappingUserInfo() 내부에서 호출됨

지난번 model 설명에서 firebase 에서 데이터를 가져오는 2가지 방식중 본인이 원하는 방식으로 사용하면 된다. 참고로 샘플1은 데이터가 많은경우 자동처리되는 로직이라서 사실은 ListView 같은 위젯에서 사용하면 좋다. 샘플2는 결과가 1개만 나올경우 사용하면 좋을것 같다. 한가지 통일된 방식으로 처리하고 싶다면 샘플1로 통일해도 좋을거 같다.

 

3. 변경된 정보를 화면에 반영하는 부분

app.dart 의 body 를 아래처럼 변경하였습니다. Obx 로 Column 을 감싸주고, Text 표시 부분에 "controller.변수명.하위변수명" 으로 표시하면 된다. ex) ${_loginUserCtrl.curUser.providerId}, ${_loginUserCtrl.curUser.uid}

"_loginUserCtrl.curUser.providerId != null" 부분을 사용한 이유는 데이터를 불러오기전에 화면이 먼저 표시되므로 화면에 짧은 순간이지만 null 로 표기되는 순간이 있어서 데이터 로딩시하는 동안에는 CircularProgressIndicator 로 처리함.

 

 

화면에 변경된 정보가 정확하게 출력되는 모습 - 구글 sns 로 로그인한 경우

 

 

 

화면에 변경된 정보가 정확하게 출력되는 모습 - 페이스북 sns 로 로그인한 경우

 

 

다음 포스팅에서는 bottomNavigationBar 를 구현하고 로그인 사용자 정보를 수정하는 기능에 대해서 알아보겠습니다.