2. flutter with supabase

최종 업데이트 : 2025-02-09

      
        
import 'package:flutter/material.dart';

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: AuthPage(),
    );
  }
}

class AuthPage extends StatefulWidget {
  const AuthPage({super.key});

  @override
  State<AuthPage> createState() => _AuthPageState();
}

class _AuthPageState extends State<AuthPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(      
      body: Center(
        child: Column(
          children: [
            const Text("이메일"),
          ],
        ),
      ),
    );
  }
}
        
      
    

state개념은 별도로 공부하심을 추천드립니다.

Scaffold 를 이용하여 body를 설정하겠습니다.

Center를 이용해 가운데 배치를 하고

column을 이용해 위젯을 세로로 배치하겠습니다.

Text를 이용해 텍스트를 출력하겠습니다.

      
        
            const Text("이메일"),
            const Text("패스워드"),
            const Text("패스워드확인"),
            TextButton(
              onPressed: () {},
              child: const Text("회원가입"),
            ),
            TextButton(
              onPressed: () {},
              child: const Text("로그인"),
            ),
        
      
    

사용될 기본컨트롤을 배치합니다.

      
        
class _AuthPageState extends State<AuthPage> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final TextEditingController _passwordCheckController =
      TextEditingController();

            const Text("이메일"),
            TextField(
              controller: _emailController,
            ),
            const Text("패스워드"),
            TextField(
              controller: _passwordController,
            ),
            const Text("패스워드확인"),
            TextField(
              controller: _passwordCheckController,
            ),
            TextButton(
              onPressed: () {},
              child: const Text("회원가입"),
            ),
            TextButton(
              onPressed: () {},
              child: const Text("로그인"),
            ),
        
      
    

입력필드들을 추가하여 다시한번 확인해봅니다.

      
        
  bool _isPasswordVisible = false;
  bool _isPasswordCheckVisible = false;

            const Text("패스워드"),
            TextField(
              controller: _passwordController,
              obscureText: !_isPasswordVisible,
              decoration: InputDecoration(
                suffixIcon: IconButton(
                  icon: Icon(
                    _isPasswordVisible
                        ? Icons.visibility
                        : Icons.visibility_off,
                  ),
                  onPressed: () {
                    setState(() {
                      _isPasswordVisible = !_isPasswordVisible;
                    });
                  },
                ),
              ),
            ),
            const Text("패스워드확인"),
            TextField(
              controller: _passwordCheckController,
              obscureText: !_isPasswordCheckVisible,
              decoration: InputDecoration(
                suffixIcon: IconButton(
                  icon: Icon(
                    _isPasswordCheckVisible
                        ? Icons.visibility
                        : Icons.visibility_off,
                  ),
                  onPressed: () {
                    setState(() {
                      _isPasswordCheckVisible = !_isPasswordCheckVisible;
                    });
                  },
                ),
              ),
            ),
        
      
    

패스워드필드임으로 obscureText을 사용합니다.

_isPasswordVisible와 _isPasswordCheckVisible의 기본값이 false임으로

!를 넣어 반대값을 사용하여 true로 obscureText를 활성화함을 이해해야합니다.

decoration을 넣어 해당 TextField flet의 can_reveal_password기능을 만듭니다.

onPressed를 이용해 해당 decoration이 눌러졌을시 변경되도록 합니다.

원하는 기능이 제대로 되었는지 실행해서 확인해봅니다.

      
         
  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }          
        
      
    

snackbar를 추가해줍니다.

      
         
  Future<void> signupRequest() {
    if (_emailController.text.isEmpty ||
        _passwordController.text.isEmpty ||
        _passwordCheckController.text.isEmpty) {
      _showSnackBar("이메일, 패스워드, 패스워드확인란을 입력해주세요.");
      return;
    }
  }

            TextButton(
              onPressed: signupRequest,
              child: const Text("회원가입"),
            ),
        
      
    

회원가입을 위해 signupRequest를 만들고

회원가입을 위한 조건을 설정하고 실행하여 간단히 테스트해봅니다.

      
         
config.dart

import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class Config {
  static String get supabaseUrl => dotenv.env['SUPABASE_URL'] ?? '';
  static String get supabaseKey => dotenv.env['SUPABASE_KEY'] ?? '';

  static Future<void> initialize() async {
    await dotenv.load(fileName: ".env");

    await Supabase.initialize(
      url: supabaseUrl,
      anonKey: supabaseKey,
    );
  }
}

final supabase = Supabase.instance.client;


main.dart

import 'package:app_flutter/config.dart';
import 'package:email_validator/email_validator.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Config.initialize();

  runApp(const MainApp());
}

  Future<void> signupRequest() async {
    if (_emailController.text.isEmpty ||
        _passwordController.text.isEmpty ||
        _passwordCheckController.text.isEmpty) {
      _showSnackBar("이메일, 패스워드, 패스워드확인란을 입력해주세요.");
      return;
    }

    if (_passwordController.text != _passwordCheckController.text) {
      _showSnackBar("패스워드가 일치하지 않습니다.");
      return;
    }

    if (_passwordController.text.length < 6) {
      _showSnackBar("패스워드는 6자리 이상이어야 합니다.");
      return;
    }

    if (!EmailValidator.validate(_emailController.text)) {
      _showSnackBar("이메일형식으로 입력해주세요.");
      return;
    }

    try {
      final response = await supabase.auth.signUp(
        email: _emailController.text,
        password: _passwordController.text,
      );
      _showSnackBar("${response.user!.email} 회원가입에 성공하였습니다.");
    } catch (e) {
      debugPrint("$e");
      _showSnackBar("오류 발생: $e");
    }
  }
        
      
    

supabase를 사용하기위해 config.dart파일을 만들고

해당 파일을 불러와서 사용합니다.

await Config.initialize(); 실행시 초기화를 대기하기위해 await을 사용하고

main() 뒤에도 async를 넣어 비동기함수로 설정합니다.

WidgetsFlutterBinding.ensureInitialized();

비동기코드인 Config.initialize()을 실행하기전에 프레임워크를 초기화합니다.

email 검사의 경우 EmailValidator를 사용합니다.

supabase.auth.signInWithPassword을 사용하기 위해 앞에 await을 추가하고

signinRequest() 뒤에도 async 를 추가합니다.

비동기로 해당 함수가 작동할때 여러번 호출하더라도

await인 함수를 결과가 나올때까지 대기하게됩니다.

flet에서는 아무것도 붙이지 않은 동기함수로 설정되어있음으로

이는 따로 한번 공부해보시는게 좋습니다.

      
         

  Future<void> signinRequest() async {
    if (_emailController.text.isEmpty || _passwordController.text.isEmpty) {
      _showSnackBar("이메일, 패스워드를 입력해주세요.");
      return;
    }

    if (_passwordController.text.length < 6) {
      _showSnackBar("패스워드는 6자리 이상이어야 합니다.");
      return;
    }

    if (!EmailValidator.validate(_emailController.text)) {
      _showSnackBar("이메일형식으로 입력해주세요.");
      return;
    }

    try {
      final response = await supabase.auth.signInWithPassword(
        email: _emailController.text,
        password: _passwordController.text,
      );
      _showSnackBar("${response.user!.email} 로그인에 성공하였습니다.");
    } catch (e) {
      debugPrint("$e");
      _showSnackBar("오류 발생: $e");
    }
  }
        
      
    

supabase.auth.signInWithPassword까지 적용하여

정상 로그인까지 확인합니다.

Related Pages

© 2024 Coding Stairs. All rights reserved.