개발/Flutter

Flutter - 코딩마스터하기|사진 업로드,게시하기1

ffuny 2021. 11. 15. 22:45
반응형

unique post key 만들기

firebase에 collection에 post와 uniqui한 키도 만들어 줄 것이다. 이미지는 firebase에 storage를 이용할 것이다. 우선 repo - helper 폴더에 generate_post_key.dart를 만들어 준다. 그리고 키를 가져오는 메소드를 만들어 주자. String getNewPostKey를 만들어주고 (UserModel userModel)을 받아온다. 그리고 파일이름 부분을 정해주는데 "${DateTime.now().millisecondsSinceEpoch}_${userModel.userKey}";로 만들어서 시간과 유저의 유니크 아이디로 조합해준다.


String getNewPostKey(UserModel userModel) => "${DateTime.now().millisecondsSinceEpoch}_${userModel.userKey}";

send post key to share screen

share_post_screen에서 postkey를 받아오기위해서 final String postKey;를 추가해주고 @required this.postKey를 추가해준다. 그리고 my_gallery에 가서 기존에 timeInMilli로 파일 이름을 지정해주는 부분을 지우고 final String postKey = getNewPostKey(Provider.of<UserModelState>(context, listen: false,).userModel);를 넣어준다. 그리고 try 안에 .png 앞의 $timeInMilli도 $postKey로 변경해준다.  그 하단에 SharePostScreen에 postKey: postKey,를 추가해주면 된다. 그리고 take_photo에서도 _attemptTakePhoto 메소드도 똑같이 변경해주면 된다.


my_gallery.dart
List<Widget> getImages(BuildContext context, GalleryState galleryState) {
    return galleryState.images
        .map((localImage) => InkWell(
              onTap: () async {
                Uint8List bytes = await localImage.getScaledImageBytes(
                    galleryState.localImageProvider, 0.3);

                final String postKey =
                getNewPostKey(Provider.of<UserModelState>(context, listen: false,).userModel);
                // final String timeInMilli = DateTime.now()
                //     .microsecondsSinceEpoch
                //     .toString(); //1970-01-01 부터 millisecond의 시간
                try {
                  //((await getTemporaryDirectory()).path+'$timeInMilli.png')로 만들어도 되지만 위험성이 있어서 사용x Join 추천
                  final path = join((await getTemporaryDirectory()).path,
                      '$postKey.png'); //getTemporaryDirectory는 Future사용 .path로 임시저장폴더 주소, 파일명 순서로 경로임
                  File imageFile = File(path)..writeAsBytesSync(bytes);

                  Navigator.of(context).push(MaterialPageRoute(
                      builder: (_) => SharePostScreen(imageFile,postKey: postKey,)));
                } catch (e) {}
              },
              child: Image(
                fit: BoxFit.cover,
                image: DeviceImage(localImage ,scale: 0.2,),
              ),
            ))
        .toList();
  }
take_photo.dart
  void _attemptTakePhoto(CameraState cameraState, BuildContext context) async {
    final String postKey =
        getNewPostKey(Provider.of<UserModelState>(context, listen: false,).userModel);
    // final String timeInMilli = DateTime.now()
    //     .microsecondsSinceEpoch
    //     .toString(); //1970-01-01 부터 millisecond의 시간
    try {
      //((await getTemporaryDirectory()).path+'$timeInMilli.png')로 만들어도 되지만 위험성이 있어서 사용x Join 추천
      final path = join((await getTemporaryDirectory()).path,
          '$postKey.png'); //getTemporaryDirectory는 Future사용 .path로 임시저장폴더 주소, 파일명 순서로 경로임
      await cameraState.controller.takePicture(path);

      File imageFile = File(path);

      Navigator.of(context).push(MaterialPageRoute(
          builder: (_) => SharePostScreen(
                imageFile,
                postKey: postKey,
              )));
    } catch (e) {}
  }

app bar layout on share post

이미지 공유하는 부분의 레이아웃을 바꿔보자. share_post_screen.dart에서 Image.file을 Scaffold로 감싸준다. 그리고 appbar:AppBar()를 넣어준다. title에는 Text로 New Post 를 넣어주고 actions 에는 FlatButton을 넣어줘서 child에 Text로 Share를 해주고 textScaleFactor은 1.4 글자색을 blue를 해주면 appBar 부분은 완성이다.


  Widget build(BuildContext context) {
    return Scaffold(
      body: Image.file(imageFile),
      appBar: AppBar(
        title: Text("New Post"),
        actions: [
          FlatButton(
            onPressed: () {},
            child: Text(
              "Share",
              textScaleFactor: 1.4,
              style: TextStyle(
                color: Colors.blue,
              ),
            ),
          ),
        ],
      ),
    );
  }

caption part in share post body layout

이미지를 올릴때 글 부분과 사진을 임시적으로 보는 앱바 바로 하단의 한줄짜리 부분이다. 이를 위해서 image.file를 ListTile로 감사준다. 그리고 ListTile를 ListView로 다시한번 감싸준다. leading부분에 image부분을 넣어주고 width에 size.width/6, height도 똑같이 해준다. fit에 BoxFit.cover로 해주면 된다. title 부분은 글 내용 부분으로 TextField를 이용한다. decoration 옵션에 InputDecoration을 넣어주고 hintText에 'Write a caption'을 해준다. 그럼 밑줄이 나오는데 이를 해결하기 위해 InputDecoration에 border에 InputBorder.none을 해주면 된다.


      body: ListView(
        children: [
          ListTile(
            contentPadding: EdgeInsets.symmetric(
              vertical: common_gap,
              horizontal: common_gap,
            ),
            leading: Image.file(
              imageFile,
              width: size.width / 6,
              height: size.width / 6,
              fit: BoxFit.cover,
            ),
            title: TextField(
              decoration: InputDecoration(
                  hintText: 'Write a caption....', border: InputBorder.none),
            ),
          ),
        ],
      ),

section button layout in share post

이미지 캡션을 달아주는 부분 아래에 태그와 위치를 추가하는 부분을 만들어 보자. 모양을 보면 ListTile로 만들어 주면 될 것으로 보인다. 우선 Divider로 칸을 나눠준다. color은 grey[300]으로 해주고 thickness 1, height 1 로해준다. 이를 get _divider =>의 메소드로 빼준다. 그리고 그 아래에 ListTile로 title에 Text에 'Tag People' 를 해주고 style에 FntWeight.w400으로 두께를 준다. traing는 Icons.navigate_next로 준다. dense는 true로 해주고 contentPadding를 symmetric으로 horizontal에 common_gap만큼 주면 된다. 이 부분은 add location 과 똑같으므로 메소드로 _sectionButton(String title)로 빼줘서 title 부분만 받아서 쓴다.


      body: ListView(
        children: [
          _captionWithImage(),
          _divider,
          _sectionButton('Tag People'),
          _divider,
          _sectionButton('Add Location'),
        ],
      ),
  Divider get _divider =>
     Divider(
          color: Colors.grey[300],
          thickness: 1, //진짜 선의 두께를 나타내는 부분 이부분 외는 흰색임
          height: 1, // 선이 나오는 부분이 아니라 패딩같이 차지하는 범위라 생각하면됨
        );


  ListTile _sectionButton(String title) {
    return ListTile(
      title: Text(
        title,
        style: TextStyle(fontWeight: FontWeight.w400),
      ),
      trailing: Icon(
        Icons.navigate_next,
      ),
      dense: true,
      contentPadding: EdgeInsets.symmetric(
        horizontal: common_gap,
      ),
    );
  }

 

반응형