LoginForm
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../../_core/constants/size.dart';
import '../../../../widgets/custom_auth_text_form_field.dart';
import '../../../../widgets/custom_elavated_button.dart';
import '../../../../widgets/custom_text_button.dart';
class LoginForm extends ConsumerWidget {
const LoginForm({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Form(
child: Column(
children: [
CustomAuthTextFormField(
title: "Username",
),
const SizedBox(height: mediumGap),
CustomAuthTextFormField(
title: "Password",
obscureText: true,
),
const SizedBox(height: largeGap),
CustomElevatedButton(
text: "로그인",
click: () {
Navigator.popAndPushNamed(context, "/post/list");
},
),
CustomTextButton(
text: "회원가입 페이지로 이동",
click: () {
Navigator.pushNamed(context, "/join");
},
),
],
),
);
}
}
LoginBody
import 'package:flutter/material.dart';
import 'package:flutter_blog/_core/constants/size.dart';
import 'package:flutter_blog/ui/pages/auth/login_page/widgets/login_form.dart';
import 'package:flutter_blog/ui/widgets/custom_auth_text_form_field.dart';
import 'package:flutter_blog/ui/widgets/custom_elavated_button.dart';
import 'package:flutter_blog/ui/widgets/custom_logo.dart';
import 'package:flutter_blog/ui/widgets/custom_text_button.dart';
class LoginBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: [
const CustomLogo("Blog"),
LoginForm(),
],
),
);
}
}
login_form_notifier.dart
//
// 창고 데이터 설계
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logger/logger.dart';
import '../../_core/utils/validator_util.dart';
class LoginModel {
// 각 필드 사용자 입력 값 관리 변수
final String username;
final String password;
// 각 입력 필드 검증 에러 메세지 관리 변수
final String usernameError;
final String passwordError;
LoginModel(
this.username,
this.password,
this.usernameError,
this.passwordError,
);
LoginModel copyWith(
{String? username,
String? password,
String? usernameError,
String? passwordError}) {
return LoginModel(
username ?? this.username,
password ?? this.password,
usernameError ?? this.usernameError,
passwordError ?? this.passwordError,
);
}
// 디버그 용
@override
String toString() {
return 'LoginModel{username: $username, password: $password, usernameError: $usernameError, passwordError: $passwordError}';
}
} // end of LoginModel class
// 창고 메뉴얼 설계
class LoginFormNotifier extends Notifier<LoginModel> {
@override
LoginModel build() {
return LoginModel("", "", "", "");
}
// 사용자명 입력시 : 즉시 검증 + 상태 업데이트 기능 구현
void username(String username) {
final String error = validateUsername(username);
Logger().d(error);
state = state.copyWith(
username: username,
usernameError: error,
);
}
// 비밀번호 입력시: 즉시 검증 + 상태 업데이트 기능 구현
void password(String password) {
String passwordError = validatePassword(password);
if (passwordError.trim().isEmpty) {
Logger().d(password);
} else {
Logger().d(passwordError);
}
state = state.copyWith(password: password, passwordError: passwordError);
}
bool validate() {
final usernameError = validateUsername(state.username);
final passwordError = validatePassword(state.password);
return usernameError.isEmpty && passwordError.isEmpty;
}
} // end of LoginFormNotifier
// 실제 창고를 메모리에 올리자 - 전역 변수로 관리
final loginFormProvider =
NotifierProvider<LoginFormNotifier, LoginModel>(() => LoginFormNotifier());
// loginFormProvider --> LoginFormNotifier() --> LoginModel()
// ref.read(loginFormProvider); --> LoginModel()
// ref.read(loginFormProvider.notifier); --> LoginFormNotifier()
LoginForm + 상태관리 연결 처리
import 'package:flutter/material.dart';
import 'package:flutter_blog/providers/form/login_form_notifier.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../../_core/constants/size.dart';
import '../../../../widgets/custom_auth_text_form_field.dart';
import '../../../../widgets/custom_elavated_button.dart';
import '../../../../widgets/custom_text_button.dart';
class LoginForm extends ConsumerWidget {
const LoginForm({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
LoginModel loginModel = ref.watch(loginFormProvider);
LoginFormNotifier loginFormNotifier = ref.read(loginFormProvider.notifier);
return Form(
child: Column(
children: [
CustomAuthTextFormField(
title: "Username",
errorText: loginModel.usernameError,
onChanged: (value) {
loginFormNotifier.username(value);
},
),
const SizedBox(height: mediumGap),
CustomAuthTextFormField(
title: "Password",
errorText: loginModel.passwordError,
onChanged: (value) {
loginFormNotifier.password(value);
},
obscureText: true,
),
const SizedBox(height: largeGap),
CustomElevatedButton(
text: "로그인",
click: () {
// 검증
bool isValid = loginFormNotifier.validate();
if (isValid) {
// 서버로 로그인 통신 요청
// 서버로 로그인 요청 성공 한다면 페이지 이동 ...
Navigator.popAndPushNamed(context, "/post/list");
} else {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text("유효성 검사 실패")));
}
},
),
CustomTextButton(
text: "회원가입 페이지로 이동",
click: () {
Navigator.pushNamed(context, "/join");
},
),
],
),
);
}
}'Flutter' 카테고리의 다른 글
| 블로그 프로젝트 - 로그아웃 기능 연결 및 UI 수정 (0) | 2025.09.04 |
|---|---|
| 블로그 프로젝트 - 사용자 세션(로그인 상태) 관리 하기 (1) | 2025.09.01 |
| 블로그 프로젝트 - 회원가입 폼 상태 관리 (1) | 2025.08.22 |
| 블로그 프로젝트 - main.dart 코드 리뷰 (0) | 2025.08.22 |
| 창고 이야기로 배우는 Riverpod 예제 코드 (3) | 2025.08.22 |