사용자가 의견을 전달하기 위한 화면을 만든다. (진행중이라서 내용이 변경될 수 있음.)
전달하는 정보는,
- 이름,
- 이메일,
- 내용
으로 구성한다. (추가적으로 플랫폼 종류, 버전정보를 포함한다.)
대략적인 화면 구성은 아래와 같다.
라우터 추가
라우터 내용은 lib/route/routes.dart 파일에서 추가한다.
./lib/route/
└── routes.dart
/contact
이름으로 GetPage 를 추가 한다.
class Routes {
...
static const contact = '/contact';
static const defaultTransition = Transition.downToUp;
static final pages = <GetPage>[
...
GetPage(
name: contact,
page: () => const ContactPage(),
binding: ContactBinding(),
transition: defaultTransition,
),
...
];
}
전체내용은 이곳에서 확인 ⇨ routes
화면 파일 생성
lib/view/contact/page/contact_page.dart 파일을 만든다. (binding, controller, page 파일을 같이 만든다.)
./lib/view/contact
├── organism
└── page
├── contact_binding.dart
├── contact_controller.dart
└── contact_page.dart
contact_controller.dart
class ContactController extends GetxController {
final formKey = GlobalKey<FormState>();
var nameController = TextEditingController();
var emailController = TextEditingController();
var contentController = TextEditingController();
Future send() async {}
}
데이터 전송을 위한 Form Key 생성한다.
이름, 이메일, 내용을 입력하기 위한 컨트롤러를 생성한다.
전송 부분은 이후에 완성하기로 한다.
contact_binding.dart
class ContactBinding implements Bindings {
@override
void dependencies() {
Get.put(ContactController());
}
}
contact_page.dart
class ContactPage extends GetView<ContactController> {
const ContactPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const BasicAppbar('문의하기'),
body: SingleChildScrollView(
child: SmallPadding(
child: buildForm(),
),
),
);
}
}
앱바에 공통 스타일을 적용하기 위해서 BasicAppbar 를 사용한다.
공통 Padding 적용을 위해서 SmallPadding 을 사용한다.
화면 구성
이름, 이메일, 내용, 저장 버튼을 Column 으로 구성한다.
buildForm() {
return Form(
key: controller.formKey,
child: Column(
children: [
buildName(),
buildEmail(),
buildContent(),
MainButton(),
],
),
);
}
이름 필드
buildName() {
return TextFormField(
decoration: InputDecoration(labelText: t.label.name),
controller: controller.nameController,
textInputAction: TextInputAction.done,
onSaved: (String? newValue) => newValue?.trim(),
validator: (String? value) => ValidatorUtil.minLength(value, length: 1),
);
}
라벨은 다국어 지원을 위해서 slang 을 사용하였다.
ValidatorUtil
유효성 검증 함수들을 한곳으로 모은다.
class ValidatorUtil {
static String? minLength(String? value, {int length = 1}) {
if (value == null || value.isEmpty || value.trim().length < length) {
if (length == 1) return t.validator.more_than_one_length;
return t.validator.more_than_length(length: length);
}
return null;
}
static String? email(String? value) {
final emailReg = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (value == null || emailReg.hasMatch(value) == false) {
return t.validator.email_format;
}
return null;
}
}
이메일 필드
buildEmail() {
return TextFormField(
decoration: InputDecoration(labelText: t.label.email),
controller: controller.emailController,
textInputAction: TextInputAction.done,
onSaved: (String? newValue) => newValue?.trim(),
validator: (String? value) => ValidatorUtil.email(value),
);
}
내용 필드
buildContent() {
return TextFormField(
decoration: InputDecoration(labelText: t.label.content),
controller: controller.contentController,
textInputAction: TextInputAction.done,
onSaved: (String? newValue) => newValue?.trim(),
validator: (String? value) => ValidatorUtil.minLength(value, length: 10),
minLines: 5,
maxLines: 10,
);
}
저장 버튼
폼을 검사하고 저장을 진행한다.
문의하는 내용이니 서버로 전송하도록 하자.
MainButton(
onPressed: () async {
if (controller.formKey.currentState!.validate()) {
controller.formKey.currentState!.save();
var res = await controller.send();
if (res != null) {
Get.snackbar(
t.title.contact.send,
t.message.contact.after_send,
);
Get.back();
}
}
},
text: t.button.send),
화면
여기까지 진행한 화면이다.
추가 정보
문의한 사용자의 환경에 대한 정보를 얻기 위해서, 플랫폼 정보, 패키지 정보를 추가한다.
사용한 라이브러리 목록
pubspec.yaml 에 추가
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
...
package_info_plus: ^4.0.2
platform_info: ^4.0.2
추가 정보는 SettingService 에서 관리한다.
class SettingService extends GetxService {
static SettingService get to => Get.find();
late PackageInfo packageInfo;
late String appName, packageName, version, buildNumber;
late Platform platform;
init() async {
packageInfo = await PackageInfo.fromPlatform();
appName = packageInfo.appName;
packageName = packageInfo.packageName;
version = packageInfo.version;
buildNumber = packageInfo.buildNumber;
platform = Platform.instance;
}
}
서비스 파일의 위치는 다음과 같다.
./lib/service/
├── ...
├── setting_service.dart
└── ...
서비스 파일이니까, system 에서 추가한다.
class System {
static Future init() async {
WidgetsFlutterBinding.ensureInitialized();
initializeJsonMapper(); // dart_json mapper 초기화
putServices();
await initServices();
}
static putServices() {
...
Get.put(SettingService());
...
}
static initServices() async {
...
await SettingService.to.init();
...
}
}
링크
'Programming > Flutter' 카테고리의 다른 글
일상기록을 위한 서비스를 만든다 (0) | 2023.07.10 |
---|---|
[flutter] layoutbuilder (0) | 2023.03.06 |
mobx - 기본구성 (0) | 2020.09.19 |
[Flutter] json_serializable 사용하기 (0) | 2019.06.13 |
댓글