/firebase1

Firebase1 with Auth and CRUD

Primary LanguageDart

firebase1

################################################################################################# Background image 는 어떻게 넣을까? 매번 새로운 화면이 그려지는데 아마도 MatrialApp 이러곳에서 바꾸지 않을까???

  • 꼭 기억하자. assets 디렉토리는 맨 바깥으로 보낸다. lib 안에 아니다. 기억해라. 당연히 Home 에서 바꾸어야지.. body: Container( decoration: BoxDecoration( image: DecorationImage( fit : BoxFit.cover, image: AssetImage('assets/coffee_bg.png'), ) ), child: BrewList()),

################################################################################################# FireStore 에 데이터를 저장 : settings_form.dart 에 ElevatedButton 부분

  • 기존에 걸 그대로 사용했음.. Future updateUserData(String sugars, String name, int strength) async { return await brewCollection.doc(_uid).set({ 'sugars' : sugars, // 여기 보이지? key 와 value 가 들어간다. type 은 어떻게 정할까? 'name' : name, 'strength' : strength, }); }

  •               ElevatedButton(
                  // FireStore 에 데이터를 저장한다.
                  // RaisedButton 대용
                  style: ElevatedButton.styleFrom(primary: Colors.pink[400]),
                  onPressed: () async {
                    if (_formKey.currentState != null) {
                      if (_formKey.currentState!.validate()) {
                        await DatabaseService(uid: user.uid).updateUserData(
                            _currentSugars ?? userData.sugars, // null 입력 해결 베스트
                            _currentName ?? userData.name,
                            _currentStrength ?? userData.strength
                        );
                      }
                      Navigator.pop(context); // BottomSheet 이제 없어진다.
                    }
                  },
                  child: Text(
                    "Update",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
    

################################################################################################# 그러면 StreamBuilder 부분은 결국 StreamProvider 과 기능이 같은 것인가????????????? 같은 기능을 하지만 같은 위젯에서 값을 바로 받을 때 StreamBuilder 를 사용한다. 왜냐면 계속 build 를 하기 때문에 결국 App 이 커지면 StreamProvider 를 사용해야 하는구나. https://stackoverflow.com/questions/59737116/flutter-with-firestore-streambuilder-vs-streamprovider 내가 이해하지 못했던 부분. 새로운 Stream 인데 Document 와 관련된거 같은데.. 현재 BottomSheet 와 list item 을 선택했을 때의 관계를 만드는 것 같다.

  • uid 와 document 와 관련 user data model 사용하기 위해서 userData class 를 만들었고

  • 그걸 사용하기 위해서 database.dart 에서 Stream 를 받기 위한 함수를 만들었다. 알지? UserData 로 변환하는 함수도 거기에 같이 있다는 걸..

  • SettingsForm class 에서 작업하는데 이번에는 StreamBuilder 를 사용할것이다.

  • setting_form.dart 의 Form() 을 StreamBuilder 로 감싼다.

    return StreamBuilder( stream: DatabaseService(uid: user.uid).userData, // provider 에서 제공하는 user 를 가지고 stream 을 userData 를 stream 으로 선택하였다. 기억해라. userData 는 get 함수이다. builder:(context, snapshot) { return Form( key: _formKey, child: Column( children: [ Text( 'Update your brew settings.',

  • 여기부분은 이제 if 문으로 작업을 하니깐 settings_form.dart 전체를 다시 보도록 하자.

################################################################################################# BottomSheet 사용 - 함수안에(context 있는함수) 함수를 또 정의하는게 가능하다. 와우 ################################################################################################# 항상 사용자 정의 위젯을 사용하려고 시도해보자.. 여기서는 지금 BrewTile 이라는 ListTile 을 만들고 있다.

################################################################################################# BrewModel 을 만들어서 사용자정의 데이터 클래스를 만들어준다.

  • 원칙 1 : 사용자 클랙스 만들기

  • 원칙 2 : 데이터를 연결하는 dart 파일에서 변환 함수를 만들기 (database.dart/_brewListFromSnapshot(QuerySnapshot snapshot))

  • 원칙 3 : map 함수를 사용하여 변환 List _brewListFromSnapshot(QuerySnapshot snapshot) { return snapshot.docs.map((doc) { Map<String, dynamic> d = doc.data()! as Map<String, dynamic>; // 각 doc 값이 Map 으로 1:1로 맵핑이 되잖아. 그래서 이게 가능한거지. return BrewModel( name: d['name'] ?? '', // null 이면 sugars: d['sugars'] ?? '0', strength: d['strength'] ?? 0 ); }).toList(); }

  • 이제 해당 데이터를 brew_list.dart 에서 사용한다. 어떻게? 자동으로 넘어오는 provider 를 사용해서.. ㅋㅋㅋ #################################################################################################

  • 데이터를 화면에 보여줄텐데 데이터가 변경이되어도 바로바로 보여줄 수 있도록 Stream 을 사용한다.

  • SnapShot 을 받을건데 그안에 모든 Document 들이 들어있다.

  • database.dart 에 stream 함수를 만든다.

  • 이제 home.dart 에서 해당 Stream 을 사용할 거다. return StreamProvider<List?>.value( // initialData 가 null 이 되기 위해서는 List? 이렇게 되어야 한다. value: DatabaseService().brews, initialData: null, child: Scaffold( 이렇게 하면 이제 하위의 모든 위젯에서 자동으로 QuerySnapshot 을 갱신할 수 있게된다. 왜냐면 후손들이 듣고 있거덩.. ^^

  • 화면에 보여줄 brew_list.dart 를 만들고 그안에서 데이터를 받는걸 테스트 한다. @override Widget build(BuildContext context) {

    final brews = Provider.of(context); print(brews.docs); for (var doc in brews.docs) { print(doc.data()); } return Container(); }

################################################################################################# User Data for FireStore

  • name, sugars, strength
  • 해당 유저가 해당 FireStore 를 어떻게 연결할래? Firebase uid 를 생성한다. 그 uid 도 등록한다.
  • DatabaseService class 에서 함수들을 만들어 준다.
  • (여기서 중요한것은 레코드 하나에 User 정보 다 넣는다. )
  • 'sugars' : sugars, // 여기 보이지? key 와 value 가 들어간다. type 은 어떻게 정할까?
  • registerWithEmailAndPassword 혹은 sign - in 을 했을 때 uid 를 이용해서 document 를 선택해준다. (which document belongs to which user by uid) <---- 이거 너무 중요하다. // create a new document for the user with the uid if (user != null) { await DatabaseService(uid: user.uid).updateUserData('0', 'new crew member', 100); }

################################################################################################# FireStore

  • go to Console and choose FireStore and create FireStore
  • 나중에 test mode 에 대해서 수정해야겠지.

################################################################################################# Loading Widget

  • flutter_spinkit 4.0.0
  • 새로운 Loading 위젯을 만든다.
  • bool loading = false; // sign in page 에 local variable 로 넣어준다.
  • 로컬 validation 이 끝나고 나면 loading = true 로 만들고 에러가 나면 loading = false 로 해주고
  • 이제 맨 상단에서 loading 이 true 이면 Loading() false 이면 Scaffold 실행
  • 이게 왜 가능하냐면 후속으로 Firebase validation 이 이루어지고 나면 거기서 다시 Home 화면으로 가게되는 이벤트가 실행되기때문이지. 아주 좋아..! ################################################################################################# TextFormField Decoration 할 떼
  • decoration: textInputDecoration.copyWith(labelText: 'Password'),
  • const textInputDecoration(labelText : "email", .....) 이렇게 만들어놓으면 반복할 필요가 없다. ################################################################################################# Stream 과 StreamProvider 그리고 Provider.of<>(context) 사용법
  • Stream 은 정해놓은 타입을 계속적으로 감시하겠다는 것이고 authStateChanges() 함수와 map() 함수를 통해서 나의 UserModel 을 지속적으로 받겠다는 의미
  • Stream Provider 는 Stream 을 연결해놓고 이제부터 계속 감시하다가 만약 데이터가 달라지면 각 자식들에게 통보
  • Provider.of<>(context) 사용하는 애들이 다시금 데이터를 받아서 그데이터를 이용해 새롭게 rebuild 하게 된다. ################################################################################################# Sign in & Register toggle 과 setState 로 왔다갔다 하기
  • showSignIn = true 불리언 값을 만든다.
  • showSignIn 에 따라 네비게이션 하게 하고
  • toggleView 함수를 만들고 setState(()=> showSignIn = !showSignIn) 해주고
  • SignIn() 과 Register() 에 함수를 넘겨준다. SignIn(toggleView : toggleView);
  • SignIn({Function toggleView}) : _toggleView = toggleView;
  • final Function toggleView; ################################################################################################# Validate 하고 값을 Firebase 에서 Validate 하고 결과값으로 데이터를 전달하는 방법
  • final _formKey = GlobalKey(); // Form 을 구별하기 위해 사용한다.
  • String email = ''; String password = ''; String error = '';
  • Form(key : _formKey,)
  • TextFormField(validator : (val) =>)); // null 값 체크, isEmpty, length
  • TextFormField(onChanged : (val) => setState(() => email = val);
  • _auth.registerWithEmailAndPassword() 함수 작성
  • ElevatedButton(onPressed : async {
    if (_formKey.currentState != null) { // null 조건문 if (_formKey.currentState!.validate()) { // 폼키를 가지고 현재 들어온 값들을 가지고 validation 을 진행한다. dynamic result = await _auth.registerWithEmailAndPassword(email: email, password: password); if (result == null) { // error 이라면 setState(() => error = 'please supply a valid email'); print(error); } } } })
  • 내가 validate 를 하고 Firebase 가 validate 를 한번 더 하고 결과값에 따라 반응
  • 이후에는 Stream 을 계속 감시하고 있기 때문에 authStateChange() 함수로 새로운 유저값의 UserModel 을 만들고 Listening 하고 있는 자식들을 변경하게 된다. ################################################################################################# FireStore 에서 Collection 과 Document 를 만들었을 때 데이터를 구분하는 방법
  • Collection : 레코드를 가지고 있는 큰 주제 즉 테이블과 같은 개념으로 생각해도 되는거지. 이 개념은 user 로 나눈게 나을 것 같다.
  • 실제로는 : Brews 라고 Collection 을 만들고 있다. 어떤 목적을 기준으로 Collection 을 만드는 것 같다.
  • Document : key, value 값으로 나누어져 있으니깐. 그걸 나누는데 커피의 농도, 설탕의 숫자, 여러가지 user 가 가지질 수 있는 그런 것들을 다 key, value 값으로 나누어서 넣어줄 수 있다는 거지.
  • 여기서 알아야 할 것은 Firebase 가 유니크한 ID 를 생성해 준다는 거다. Document 별로 맞지? 여기서는 User UID 를 Document 의 ID 로 사용하였다. #################################################################################################
  • pubspec.yaml 파일에
  • firebase_auth 설치
  • cloud_firestore 설치 ################################################################################################# // firebase install 파이어베이스 설치 // : 초기 설치방법 // https://firebase.google.com/docs/flutter/setup?platform=web : google official documents // https://pub.dev/packages/firebase_core/install : firebase core package 설치해야함 // 그리고 마지막 투두:4 부분 해줘야 함 : 초기 설치방법 4:03 에 있는 부분 #################################################################################################