Flutter

Flutter Day 16: 블로그 만들기 - PostRepository, PostListPage 만들어보기

@leem 2025. 2. 7. 11:24

Flutter 앱에서 게시글을 관리하기 위해 PostRepository를 만들고, 이를 활용한 PostListPage를 구현하는 과정에 대해 다룹니다. 또한, 사용자 로그인 및 로그아웃 처리를 위한 CustomDrawer까지 설명합니다.


1. PostRepository 구현하기

게시글 데이터를 서버와 연동하기 위해 PostRepository를 작성합니다.

이를 통해 게시글 조회, 생성, 수정, 삭제 등의 기능을 제공합니다.

PostRepository의 역할

  • 게시글 목록 조회 (findAll)
    → 페이지 번호를 입력받아 해당 페이지의 게시글을 서버에서 가져옵니다.
  • 게시글 상세 조회 (findById)
    → 특정 게시글의 ID를 이용해 상세 정보를 가져옵니다.
  • 게시글 삭제 (delete)
    → 특정 ID를 가진 게시글을 삭제합니다.
  • 게시글 생성 (save)
    → 새로운 게시글을 생성하고 서버에 저장합니다.
  • 게시글 수정 (update)
    → 기존 게시글을 수정하여 서버에 반영합니다.
class PostRepository {
  const PostRepository();

  // 게시글 목록 조회
  Future<Map<String, dynamic>> findAll({int page = 0}) async {
    Response response = await dio.get('/api/post', queryParameters: {'page': page});
    return response.data;
  }

  // 게시글 상세 조회
  Future<Map<String, dynamic>> findById({required int id}) async {
    Response response = await dio.get('/api/post/$id');
    return response.data;
  }

  // 게시글 삭제
  Future<Map<String, dynamic>> delete({required int id}) async {
    Response response = await dio.delete('/api/post/$id');
    return response.data;
  }

  // 게시글 생성
  Future<Map<String, dynamic>> save(Map<String, dynamic> reqData) async {
    Response response = await dio.post('/api/post', data: reqData);
    return response.data;
  }

  // 게시글 수정
  Future<Map<String, dynamic>> update(int id, Map<String, dynamic> reqData) async {
    Response response = await dio.put('/api/post/$id', data: reqData);
    return response.data;
  }
}

2. PostListPage 만들기

이제 게시글 목록을 표시하는 PostListPage를 구현합니다.

PostListPage의 역할

  • Drawer와 연결하여 사용자 메뉴 제공
  • 게시글 목록을 보여주는 UI 작성
 
import 'package:class_f_story/ui/widgets/custom_drawer.dart';
import 'package:flutter/material.dart';

class PostListPage extends StatelessWidget {
  final scaffoldKey = GlobalKey<ScaffoldState>();

  PostListPage({super.key});

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        key: scaffoldKey,
        drawer: CustomDrawer(scaffoldKey),
        appBar: AppBar(
          title: Text('f-story'),
        ),
      ),
    );
  }
}

3. CustomDrawer를 활용한 로그아웃 기능

사용자가 로그인된 상태에서 로그아웃할 수 있도록 CustomDrawer에 로그아웃 버튼을 추가합니다.

import 'package:class_f_story/data/gvm/session_gvm.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class CustomDrawer extends ConsumerWidget {
  final GlobalKey<ScaffoldState> scaffoldKey;
  const CustomDrawer(this.scaffoldKey, {super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    SessionGVM vm = ref.read(sessionProvider.notifier);
    return Container(
      width: 250,
      color: Colors.white,
      child: Column(
        children: [
          TextButton(
            onPressed: () {
              scaffoldKey.currentState!.openEndDrawer();
              Navigator.pushNamed(context, 'post/write');
            },
            child: Text('글쓰기'),
          ),
          Divider(),
          TextButton(
            onPressed: () async {
              await vm.logout();
            },
            child: Text('로그아웃'),
          ),
          Divider(),
        ],
      ),
    );
  }
}

4. PostWritePage 구현

게시글을 작성할 수 있는 화면을 추가합니다.

UI 컴포넌트 분리

  • CustomTextFormField (단일 줄 입력)
  • CustomTextArea (여러 줄 입력)
  • CustomElevatedButton (버튼)

PostWritePage 구성

import 'package:class_f_story/ui/pages/post/write_page/widgets/post_write_body.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: PostWriteBody(),
    );
  }
}
 

PostWriteBody (UI 레이아웃)

import 'package:class_f_story/ui/pages/post/write_page/widgets/post_write_form.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        children: [
          Flexible(
            child: PostWriteForm(),
          ),
        ],
      ),
    );
  }
}

PostWriteForm (게시글 입력 및 저장 버튼)

import 'package:class_f_story/ui/widgets/custom_elevated_button.dart';
import 'package:class_f_story/ui/widgets/custom_text_area.dart';
import 'package:class_f_story/ui/widgets/custom_text_form_field.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class PostWriteForm extends ConsumerWidget {
  final _titleController = TextEditingController();
  final _contentController = TextEditingController();

  PostWriteForm({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Form(
      child: ListView(
        shrinkWrap: true,
        children: [
          CustomTextFormField(hint: '제목', controller: _titleController),
          SizedBox(height: 10),
          CustomTextArea(hint: '내용', controller: _contentController),
          SizedBox(height: 20),
          CustomElevatedButton(
            text: '작성 완료',
            click: () {
              // 게시글 저장 로직 추가 예정
            },
          )
        ],
      ),
    );
  }
}

정리

  1. PostRepository를 통해 게시글 CRUD API와 연동
  2. PostListPage를 만들어 게시글 목록을 표시
  3. CustomDrawer를 활용하여 로그아웃 기능 추가
  4. PostWritePage를 구현하여 사용자가 게시글을 작성할 수 있도록 구성