DAY 27 : 개인 프로젝트 — view (1)

Pt J·약 23시간 전
post-thumbnail

DAY 27 : 개인 프로젝트 — view (1)

작업 일정

  • #1 프로젝트 구조 설계
  • #2 [view] StatefulShellRoute 와 go_route
  • #3 [view] 홈 탭과 운동 세션 화면 뼈대 잡기

#1 프로젝트 구조 설계

Andorid Studio에서 새 프로젝트를 생성하고 README.md에 프로젝트 설명을 간단히 적는다. 우선 핵심적인 부분만 적어놓고 initial commit을 남긴 뒤, 추후 프로젝트 진행에 따라 보완하기로 했다.

그리고 기획했던 디자인 토큰을 프로젝트에 반영하기 위해 lib/theme.dart 에 주요 테마 설정을 적어놓았다. 일단 생각나는 것만 적어놓긴 했는데 나중에 필요에 따라 추가하거나 수정하도록 하겠다. 버튼 같은 건 일단 Claude Deisgn으로 작업했던 Design Foundation을 기반으로 느낌만 잡아 놓아서 UI를 앉혀 본 후에 조정을 하게 될 듯하다.

#2 [view] StatefulShellRoute 와 go_route

간단히 말해 하단 네비게이션 바를 만들고 route를 잡는 거다. 화면을 설계할 때 애초에 route URL을 화면 식별자로 사용했기에 그걸 거의 그대로 코드로 옮기며 검토하는 정도다.

go_router package는 그새 18.0.1으로 버전이 올라 있다. 18번대의 Dart 최소 버전은 3.12이고 Flutter 최소 버전은 3.44인데 우리 작업 환경의 Dart SDK는 3.12.2이고 Flutter SDK는 3.44.4이므로 문제 없이 사용할 수 있다.

pubspec.yaml

# 앞 부분 생략
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  go_router: ^18.0.1
# 뒷 부분 생략

실습했던 환경과의 변경점은 다음과 같은데 당장 크게 신경쓰지는 않아도 될 것 같다. route metadata 관련해서는 실습했던 것과 다르게 구현할 수 있는 부분도 있을 것 같은데 로그인 관련 코드를 작성하면서 좀 더 자세히 살펴봐야겠다.

  • Migrates to material_ui and cupertino_ui.
  • Updates minimum supported SDK version to Flutter 3.44/Dart 3.12.
  • Adds route metadata support, including inheritance and override behavior with exposure on GoRouterState.
  • Documents support for regular expression constraints in GoRoute path parameters.

URL parameter에 정규표현식을 사용하는 게 공식 기능으로 안정화되었다는 게 흥미롭다. /endpoint/:id 라는 route에서 id 에 숫자만 허용하거나 정규표현식 패턴 매칭에 따라 다른 화면으로 연결하는 게 가능한 모양이다.

하단 네비게이션을 사용하지 않는 페이지

실습 땐 없던 유형의 페이지다. 하지만 세션 진행 도중 다른 탭으로 이동하지 않도록 해야 하므로 하단 네비게이션이 없는 화면이 필요하다.

이런 경우에는 해당 route는 StatefulShellRoute.indexedStack 밖으로 빼야 한다고 한다. 그러니까 홈 탭에서만 세션에 진입하니 언뜻 보기엔 /home route 아래에 session route가 있을 것 같지만 완전히 별개의 route로 존재하는 것이다.

세션 페이지뿐만 아니라 타인의 프로필 페이지, 이용약관 및 개인정보처리방침도 이런 식으로 shell 밖에 작성된다. 그리고 실습 때와 달리 로그인 및 회원가입 관련 페이지도 shell 밖으로 빼도록 하겠다.

전반적인 route 구성

일단은 앱을 켜면 랜딩 페이지가 나오고 버튼을 누르면 홈 화면으로 이동하며 홈을 포함한 네 개 탭이 존재하는 상태로 만들었다. 각 화면은 Placeholder로 둔 채 순차적으로 구현해 나갈 것이다. 총 27개의 route가 존재한다.

route 구조

  • 랜딩 페이지 (/)
  • Stateful Shell Route
    • 홈 탭 (/home)
    • 피드 탭 (/feed)
      • 피드 내 게시물 (/feed/post/:sketch-id)
      • 피드 알림 (/feed/notifications)
    • 기록 탭 (/history)
      • 세션 상세 기록 (/history/details/:session-id)
    • 나 탭 (/me)
      • 친구 목록 (/me/friends)
        • 사용자 검색 (/me/friends/search)
      • 설정 (/me/settings)
        • 계정 설정 (/me/settings/account)
          • 비밀번호 변경 (/me/settings/account/password)
        • 캐릭터 설정 (/me/settings/character)
        • 알림 설정 (/me/settings/notifications)
  • 세션 및 운동 선택 (/session-start)
  • 세션 진행 (/session-tracking)
  • 세션 결과 (/session-result/:session-id)
    • 세션 결과 공유 (/session-result/:session-id/share)
  • 다른 사용자 프로필 (/profile/:user-id)
  • 오픈소스 라이선스 (/license)
  • 개인정보 처리방침 (/privacy)
  • 이용약관 (/tos)
  • 로그인 (/auth/login - /auth 로 접근해도 redirect)
  • 회원가입 (/auth/signup)
    • 회원가입 성공 및 이메일 인증 안내 (/auth/signup/complete)
  • 비밀번호 찾기 (auth/password)

#3 [view] 홈 탭과 운동 세션 화면 뼈대 잡기

홈 화면 (/home)

홈 화면에서는 오늘 날짜와 날씨를 띄워주며 가장 최근 운동 기록을 보여주고 (기록이 없다면 시작해 보라고 한다) 세션 시작 CTA 버튼을 띄우며 지난 일주일 동안의 기록 여부를 보여준다.

일단 날씨, 운동 기록, 사용자 프로필은 Mock 데이터를 사용하여 화면 구성을 한다. 날짜는 피드와 기록에서도 형식에 맞는 날짜를 종종 쓰게 될 테니 편하게 쓰기 위해 intl package를 사용하도록 하겠다.

pubspec.yaml

# 앞 부분 생략
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  go_router: ^18.0.1
  intl: ^0.20.2
# 뒷 부분 생략

운동 기록은 피드에서도 계속 쓸 것이므로 custom widget으로 작성한다. 그리고 주간 기록 인디케이터는 홈 화면에서만 사용하지만 코드 복잡도를 낮추기 위해 이 또한 custom widget으로 작성한다.

세션 및 운동 선택 화면 (/session-start)

어떤 운동을 선택할지 토글 스위치는 animated_toggle_switch를 사용하기로 했다. flutter_switch는 몇 년씩이나 유지보수가 안 되고 있고 flutter_toggle_swtich는 4개월 전에 첫 버전이 나와 아직 충분히 검증되지 않은 느낌이다.

pubspec.yaml

# 앞 부분 생략
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  go_router: ^18.0.1
  intl: ^0.20.2
  animated_toggle_switch: ^0.8.7
# 뒷 부분 생략

운동은 양자택일이므로 토글 스위치 방향에 따라 isJogging 의 값을 뒤집고, 이에 따라 적절한 미션 목록을 출력한다. 미션 목록은 다섯 가지 중 최대 두 개까지 선택할 수 있다. 이미 두 개가 선택되어 있는 상태에서 하나 더 선택하면 가장 처음 선택한 것이 취소되는 방식으로 하였다.

각 미션 카드는 MissionCard widget을 정의하여 사용한다. 카드가 선택되었는지 여부는 이 widget 안에 있는데 미션이 두 개 이상 선택되어 있는지 여부는 바깥에서 판단해야 하므로 SessionStartPage 에서 onTap 에 대한 callback function을 작성하여 MissionCard 로 넘겨준다.

lib/pages/session_start_page.dart

// 앞 부분 생략
  final List<int> _selectedIndices = [];
  void _handleCardTapped(int index) {
    setState(() {
      if (_selectedIndices.contains(index)) {
        _selectedIndices.remove(index);
      } else {
        if (_selectedIndices.length >= 2) {
          _selectedIndices.removeAt(0);
        }
        _selectedIndices.add(index);
      }
    });
  }
// 뒷 부분 생략

세션 진행 화면 (/session-tracking)

세션 진행 화면은 화면 설계상으로는 단순해 보이지만 추후 기능 구현 난이도가 있는 부분이다. 실시간으로 처리되어야 하는 것들도 있고 백그라운드에서 돌아가는 것들도 있고 의도치 않게 종료되었을 때에 대한 처리도 필요하다. 기능 구현 시 가장 힘써야 할 부분이지만 일단은 layout만 잡고 넘어갈 것이니 의사결정의 많은 부분을 뒤로 미룬다.

sessionId 는 [종료] 버튼 클릭 시 세션 결과 화면으로 이동할 때 필요하므로 어떻게 정해지는지 결정하고 넘어가는 게 좋을 것 같다. uuid package를 사용하여 UUID v4로 id 값을 생성하기로 했다.

이동 그래프도 일단 임의의 좌표를 넣어서 작성하는데, flutter_map package와 latlong2 package를 사용하여 좌표를 나타낸다.

pubspec.yaml

# 앞 부분 생략
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.8
  go_router: ^18.0.1
  intl: ^0.20.2
  animated_toggle_switch: ^0.8.7
  uuid: ^4.6.0
  flutter_map: ^8.3.2
  latlong2: ^0.10.1
# 뒷 부분 생략

이동 경로 뷰는 로직 붙이면서 여러 모로 손봐야 할 듯하다.

세션 일시정지 모달 (modalSessionPause)

세션 일시정지 모달은 데이터를 보여주기만 하기 때문에 단순하다. 하드코딩 되어 있는 부분을 이후에 Provider로부터 직접 받게 수정하는 정도?

세션 결과 화면 (/session-result/:session_id)

'/session-result/:session-id' 라는 route를 사용할 수 없다는 걸 발견했다! : 뒤에 오는 parameter 부분에는 '-'를 사용할 수 없다. session_id 로 하든 sessionId 로 하든 수정해야 한다. 전자가 더 나을 듯하여 session_id 로 수정하였다. 웹 URL에서는 '-'이 흔히 쓰여 route를 그렇게 작성했던 건데 go_router 의 path parameter에서는 허용하지 않는다더라.

화면이 길어서 SingleChildScrollView 로 감쌌는데 하단 버튼은 스크롤과 관련 없이 늘 맨 아래 있었으면 해서 ScaffoldbottomNavigationBar 에 버튼을 넣었다.

세션 결과 공유 화면 (/session-result/:session_id/share)

세션 결과 공유 화면에는 재사용이 많다. 스케치 이미지 뷰도 기존에 만들어 놓은 widget이고, 위치 선택 태그도 SessionStartPage 에서 조깅/라이딩 선택할 때 썼던 package를 사용하면 된다.


>>> GitHub Repository at this point (41e23e5)

profile
Peter J Online Space - since July 2020 | 아무데서나 채용해줬으면 좋겠다 (지금은 학생 때 하던 거 아무거나 공부하고 있고요, 취업시켜 주시면 그 분야로 공부할게요)

0개의 댓글