본문 바로가기

Flutter

클래스 등록하기

imagePicker를 사용하여 갤러리에 있는 image를 가지고 온다.

플러터에서 제공하는 datePicker를 활용하여 달력을 가지고 온다.

dropdownbutton위젯으로 카테고리 선택을 활용한다.

 

imagePicker 이미지 등록 정리

https://sub1-coding.tistory.com/305

 

이미지 등록하기

image_picker라이브러리를 사용한다. 다트 파일에 image picker와 dart:io를 임포트해 주자. import 'dart:io'; import 'package:image_picker/image_picker.dart'; 소스코드 import 'dart:io'; import 'package:flutter/foundation.dart'; import

sub1-coding.tistory.com

 

datePicker 달력정리

https://sub1-coding.tistory.com/304

 

datePicker 달력

DatePicker는 사용자가 날짜를 선택할 수 있게 해주는 Flutter의 Material 위젯이다. showDatePicker() 함수를 사용하여 달력을 보여준다. Flutter DateTime Picker는 쉽게 사용자가 지정할 수 있고 여러 언어로 날

sub1-coding.tistory.com

 

dropdown 버튼 정리

https://sub1-coding.tistory.com/297

 

DropDownButton

카드 결제페이지에서 할부여부 버튼을 누르면 아래와 같이 나오게 할것이다. pubdev에 있는 dropdown_button2 라이브러리 사용한다. 의존성 추가 버튼을 누르면 rebuild해서 보여주기 때문에 statefulwidget

sub1-coding.tistory.com

 

Provider 상태관리

 

lessonInsertReqDto

data값을 json으로 직렬화하여 전달해준다.

  Map<String, dynamic> toJson() => {
        "name": name,
        "photo": photo,
        "price": price,
        "place": place,
        "lessonTime": lessonTime,
        "lessonCount": lessonCount,
        "possibleDays": possibleDays,
        "curriculum": curriculum,
        "policy": policy,
        "deadline": deadline,
        "categoryId": categoryId,
        // "categoryId": categoryId,
      };

 

service

통신과 파싱을 한다.

  Future<ResponseDto> fetchlessonInsert(LessonInsertReqDto lessonReqDto) async {
    String requestBody = jsonEncode(lessonReqDto);
    Response response = await httpConnector.post(path: "/api/lesson", body: requestBody);
    ResponseDto responseDto = toResponseDto(response);
    return responseDto;
  }

 

 

 

실행화면

 

코드 실행

import 'dart:convert';
import 'dart:typed_data';

import 'package:dropdown_button2/dropdown_button2.dart';

import 'package:finalproject_front/constants.dart';
import 'package:finalproject_front/controller/lesson_controller.dart';
import 'package:finalproject_front/dto/request/lesson_req_dto.dart';
import 'package:finalproject_front/pages/lesson/components/category_period.dart';

import 'package:finalproject_front/size.dart';

import 'package:flutter/material.dart';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fluttertoast/fluttertoast.dart';

import 'package:image_picker/image_picker.dart';
import 'dart:io';

import 'package:intl/intl.dart';
import 'package:logger/logger.dart';

import 'lesson_deadline.dart';

class LessonInsertForm extends ConsumerStatefulWidget {
  final _name = TextEditingController();
  final _curriculum = TextEditingController();
  final _count = TextEditingController();
  final _place = TextEditingController();
  final _policy = TextEditingController();
  final _dateInput = TextEditingController();
  final _time = TextEditingController();
  final _price = TextEditingController();
  final _possibleDay = TextEditingController();
  final _photo = TextEditingController();

  LessonInsertForm({Key? key}) : super(key: key);

  @override
  ConsumerState<LessonInsertForm> createState() => _LessonInsertFormState();
}

class _LessonInsertFormState extends ConsumerState<LessonInsertForm> {
  XFile? pickedFile;
  ImagePicker imgpicker = ImagePicker();
  XFile? _imagefile;
  late String profileImage;
  // ValueChanged<T> select;

  final _formKey = GlobalKey<FormState>();
  late ScrollController scrollController;

  @override
  void initState() {
    super.initState();
    scrollController = new ScrollController();
  }

  void _buildShowDatePickerPop() {
    Future<DateTime?> selectedDate = showDatePicker(
      context: context,
      initialDate: DateTime.now(), //초기값
      firstDate: DateTime(2020), //시작일
      lastDate: DateTime(2023), //마지막일
      builder: (BuildContext context, Widget? child) {
        return Theme(
          data: ThemeData.dark(), //다크 테마
          child: child!,
        );
      },
    );

    selectedDate.then((dateTime) {
      Fluttertoast.showToast(
        msg: dateTime.toString(),
        toastLength: Toast.LENGTH_LONG,
        //gravity: ToastGravity.CENTER,  //위치(default 는 아래)
      );
    });
  }

  openImages() async {
    try {
      dynamic sendImage; // 디바이스 경로
      var pickedfile = await imgpicker.pickImage(source: ImageSource.gallery);
      //you can use ImageCourse.camera for Camera capture
      if (pickedfile != null) {
        _imagefile = pickedfile;
        setState(() {}); // 상태 초기화
        sendImage = _imagefile?.path;
        final encodeImage = utf8.encode(sendImage);
        List<int> data = encodeImage;
        String profileImage = base64Encode(data);
        Logger().d("레슨 이미지 : ${profileImage}");
        return this.profileImage = profileImage;
      } else {
        print("No image is selected.");
      }
    } catch (e) {
      print("error while picking file.");
    }
  }

  void scrollAnimate() {
    Future.delayed(Duration(milliseconds: 600), () {
      //0.6초 이후 키보드 올라옴
      // ViewInsets은 현재 페이지에서 내가 컨트롤 할 수 없는 영역을 뜻함,
      // bottom은 키보드가 아래에서 올라오기 때문
      scrollController.animateTo(MediaQuery.of(context).viewInsets.bottom,
          duration: Duration(microseconds: 100), // 0.1초 이후 field가 올라간다.
          curve: Curves.easeIn); //Curves - 올라갈때 애니메이션
    });
  }

  @override
  Widget build(BuildContext context) {
    LessonInsertReqDto lessonInsertReqDto = LessonInsertReqDto.origin();
    final lessonCT = ref.read(lessonController);
    Size size = MediaQuery.of(context).size;
    return Form(
      key: _formKey,
      child: ListView(
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: Column(
              children: [
                _buildImageUploader(lessonInsertReqDto),
                SizedBox(
                  height: gap_m,
                ),
                _buildTextField(scrollAnimate, fieldTitle: "서비스제목", hint: "서비스 제목자리입니다", lines: 1, fieldController: widget._name, onChanged: (value) {
                  lessonInsertReqDto.name = value;
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "커리큘럼", hint: "상세설명", lines: 6, fieldController: widget._curriculum, onChanged: (value) {
                  lessonInsertReqDto.curriculum = value;
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "수강횟수", hint: "수강횟수를 입력하세요", lines: 1, fieldController: widget._count, onChanged: (value) {
                  lessonInsertReqDto.lessonCount = int.parse(value);
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "수강시간", hint: "수강시간을 입력하세요", lines: 1, fieldController: widget._time, onChanged: (value) {
                  lessonInsertReqDto.lessonTime = int.parse(value);
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "수강장소", hint: "수강장소를 입력하세요", lines: 1, fieldController: widget._place, onChanged: (value) {
                  lessonInsertReqDto.place = value;
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "가격", hint: "가격을 입력하세요", lines: 1, fieldController: widget._price, onChanged: (value) {
                  lessonInsertReqDto.price = int.parse(value);
                }),
                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "취소 및 환불 정책", hint: "취소 및 환불 정책 작성", lines: 4, fieldController: widget._policy,
                    onChanged: (value) {
                  lessonInsertReqDto.policy = value;
                }),

                SizedBox(height: gap_l),
                _buildTextField(scrollAnimate, fieldTitle: "가능일", hint: "가능일을 입력하세요", lines: 1, fieldController: widget._possibleDay,
                    onChanged: (value) {
                  lessonInsertReqDto.possibleDays = value;
                }),
                SizedBox(height: gap_l),
                LessonDeadLine(
                  fieldController: widget._dateInput,
                  lessonInsertReqDto: lessonInsertReqDto,
                ),
                SizedBox(height: gap_l),
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      "카테고리선택",
                      style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: gap_m),
                    Container(
                      decoration: BoxDecoration(
                        border: Border.all(color: gBorderColor, width: 3),
                        borderRadius: BorderRadius.circular(15),
                      ),
                      child: DropdownButtonFormField<int?>(
                        decoration: InputDecoration(
                          hintText: '카테고리 선택',
                          enabledBorder: OutlineInputBorder(
                            borderSide: BorderSide.none,
                            borderRadius: BorderRadius.circular(15),
                          ),
                          //마우스 올리고 난 후 스타일
                          focusedBorder: OutlineInputBorder(
                            borderSide: BorderSide.none,
                            borderRadius: BorderRadius.circular(15),
                          ),
                        ),

                        // underline: Container(height: 1.4, color: Color(0xffc0c0c0)),
                        onChanged: (int? newValue) {
                          lessonInsertReqDto.categoryId = newValue;
                        },
                        items: [1, 2, 3, 4, 5, 6, 7, 8].map<DropdownMenuItem<int?>>((int? i) {
                          return DropdownMenuItem<int?>(
                            value: i,
                            child: Text({1: '뷰티', 2: '운동', 3: '댄스', 4: '뮤직', 5: '미술', 6: '문학', 7: '공예', 8: '기타'}[i] ?? '미선택'),
                          );
                        }).toList(),
                      ),
                    ),
                  ],
                ),
                SizedBox(height: gap_l),

                ElevatedButton(
                  onPressed: () {
                    Logger().d("레슨 이미지 확인 : ${profileImage}");
                    lessonInsertReqDto.photo = profileImage;
                    Logger().d("레슨 이미지 확인 : ${lessonInsertReqDto.photo}");

                    lessonCT.lessonInsert(lessonInsertReqDto: lessonInsertReqDto);
                  },
                  style: ElevatedButton.styleFrom(
                    primary: gButtonOffColor,
                    minimumSize: Size(getScreenWidth(context), 60),
                  ),
                  child: Align(
                    alignment: Alignment.center,
                    child: Text(
                      "클래스 등록하기",
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                    ),
                  ),
                )
                // _buildLessonButton(context)
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildImageUploader(LessonInsertReqDto lessonInsertReqDto) {
    return Row(
      children: [
        //open button ----------------
        _imagefile != null
            ? Container(
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(10),
                  child: Image.file(
                    File(_imagefile!.path),
                    width: 200,
                    height: 100,
                    fit: BoxFit.cover,
                  ),
                ),
              )
            : Container(
                width: 200,
                height: 100,
                decoration: BoxDecoration(
                  border: Border.all(color: gBorderColor),
                  borderRadius: BorderRadius.circular(10),
                ),
              ),
        SizedBox(width: gap_m),
        Container(
          height: 90,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                "클래스 사진 등록",
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
              ),
              SizedBox(
                height: 30,
                width: 140,
                child: ElevatedButton(
                  onPressed: () {
                    openImages();
                  },
                  style: TextButton.styleFrom(
                    backgroundColor: gContentBoxColor,
                    primary: gPrimaryColor,
                  ),
                  child: Text("이미지 선택",
                      style: TextStyle(
                        fontSize: 14,
                        fontWeight: FontWeight.bold,
                      )),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildTextField(Function scrollAnimate,
      {required String fieldTitle,
      required String hint,
      String? subTitle,
      required int lines,
      required TextEditingController fieldController,
      required ValueChanged<String>? onChanged}) {
    return Container(
      child: Column(
        children: [
          Align(
            alignment: Alignment.centerLeft,
            child: Text.rich(
              TextSpan(
                children: [
                  TextSpan(
                    text: "${fieldTitle}",
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                  if (subTitle != null)
                    TextSpan(
                      text: "${subTitle}",
                      style: TextStyle(color: gSubTextColor, fontSize: 10, fontWeight: FontWeight.bold),
                    )
                ],
              ),
            ),
          ),
          SizedBox(height: gap_m),
          TextFormField(
            onTap: (() {
              scrollAnimate;
            }),
            onChanged: onChanged,
            controller: fieldController,
            keyboardType: TextInputType.multiline,
            maxLines: lines,
            decoration: InputDecoration(
              hintText: "${hint}",
              hintStyle: TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.normal,
                color: gSubTextColor,
              ),
              //3. 기본 textFormfield 디자인 - enabledBorder
              enabledBorder: OutlineInputBorder(
                borderSide: BorderSide(color: gClientColor, width: 3.0),
                borderRadius: BorderRadius.circular(15),
              ),
              //마우스 올리고 난 후 스타일
              focusedBorder: OutlineInputBorder(
                borderSide: BorderSide(color: gClientColor, width: 3.0),
                borderRadius: BorderRadius.circular(15),
              ),
            ),
          ),
        ],
      ),
    );
  }

//possibleDays: selectedValue,

  Widget _selectCarrer(LessonInsertReqDto lessonInsertReqDto) {
    return Container(
      child: Column(
        children: [
          SizedBox(
            height: 20,
          ),
          Row(
            children: [
              Text(
                "카테고리 선택",
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                textAlign: TextAlign.center,
              ),
            ],
          ),
          SizedBox(height: 10),
          Container(
            decoration: BoxDecoration(
              border: Border.all(color: gBorderColor, width: 3),
              borderRadius: BorderRadius.circular(15),
            ),
            child: selectedCarrerButton(
              lessonInsertReqDto: lessonInsertReqDto,
            ),
            width: 400,
            height: 60,
          )
        ],
      ),
    );
  }
}

'Flutter' 카테고리의 다른 글

카드선택 페이지, 결제 정보 페이지  (0) 2022.12.21
클래스 리스트  (0) 2022.12.21
고객센터 페이지, 결제/취소 내역  (0) 2022.12.20
주문하기 페이지  (0) 2022.12.20
검색페이지  (0) 2022.12.20