Soojeong Lee

2025. 7. 25.

Soojeong Lee

2025. 7. 25.

Soojeong Lee

2025. 7. 25.

추가 및 상세페이지 작업하기

추가 및 상세페이지 작업하기

추가 및 상세페이지 작업하기

모델링 조금 고쳐보기

우선, 모든 객체가 id 프로퍼티가 있으므로 BaseModel 클래스를 만들었다.

class BaseModel {
  String? id;
}

그리고 기본적으로 추억하는 기억거리를 적은 형태의 글과 영상/사진 형태의 미디어라고 분리하여, 공통적으로 Memory 클래스에서 상속하게 했다.

import 'base.model.dart';

class Memory extends BaseModel {
  final String memo;
  final DateTime createdAt;

  Memory({required this.memo, required this.createdAt});
}

class MediaMemory extends Memory {
  final String url;
  final String location;

  MediaMemory({
    required this.url,
    required this.location,
    required super.memo,
    required super.createdAt,
  });
}

class WrittenMemory extends Memory {
  final String content;

  WrittenMemory({
    required this.content,
    required super.memo,
    required super.createdAt,
  });
}


각 추억거리 별 상세페이지

라우트를 요로코롬 분리하는 작업을 했는데, 기본적으로 위 추억거리의 종류에 따라 분기하여 각기 다른 레이아웃의 화면으로 이동하도록 처리하였다.

GoRoute(
      path: '/lost_person/:lost_person_id',
      builder: (context, state) {
        final lostPersonId = state.pathParameters['lost_person_id']!;
        return LostPersonDetailScreen(lostPersonId: lostPersonId);
      },
      routes: [
        GoRoute(
          path: '/memories',
          builder: (context, state) {
            final lostPersonId = state.pathParameters['lost_person_id']!;
            return MemoryDetailScreen(lostPersonId: lostPersonId);
          },
        ),
        GoRoute(
          path: '/item/:item_id',
          builder: (context, state) {
            final itemId = state.pathParameters['item_id']!;
            final itemType = state.uri.queryParameters['item_type'] ?? '';
            switch (itemType) {
              case 'written':
                return WrittenMemoryDetailPage(itemId: itemId);
              default:
                return MediaMemoryDetailPage(itemId: itemId);
            }
          },
        ),
      ],
    ),

위의 핵심은 나름 state.uri.queryParameters로 각 추억거리의 타입을 받아, 그에 맞는 레이아웃의 화면으로 이동하는 것이다. 이동할 때에는 이런 형태의 url을 응용한다.

context.push('/lost_person/1/item/1?item_type=media');


사진이나 영상을 보이는 상세화면은 이런 레이아웃이다.


글 형태를 보이는 상세화면은 이런 레이아웃이다.


추가 동작

추가 동작은 단순한데, 미리 만들어놓은 FAB에 모달을 띄우면 된다.

 floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: () => showModalBottomSheet(
          context: context,
          shape: const RoundedRectangleBorder(
            borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
          ),
          builder: (context) {
            return Padding(
              padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ListTile(
                    leading: const Icon(Icons.photo),
                    title: const Text('Upload Photo'),
                    onTap: () {
                      Navigator.pop(context);
                      // TODO: handle image upload
                    },
                  ),
                  ListTile(
                    leading: const Icon(Icons.videocam),
                    title: const Text('Upload Video'),
                    onTap: () {
                      Navigator.pop(context);
                      // TODO: handle video upload
                    },
                  ),
                  ListTile(
                    leading: const Icon(Icons.contact_page_outlined),
                    title: const Text('Upload a Written Memory'),
                    onTap: () {
                      Navigator.pop(context);
                      // TODO:  handle text upload
                    },
                  ),
                ],
              ),
            );
          },
        ),
      ),


개인적으로는 BottomSheet가 깔끔하다고 생각한다.


갈길이 멀긴 하지만 어쨋든 화면 쪽 핵심기능 관련된 레이아웃은 왠만하면 잡은 것 같다. 서버 동작 추가 전에 화면을 조금 더 다듬어 마무리 지을 예정.

Next Article

Next Article

Next Article

Comments

Comments

Comments