본문으로 건너뛰기

작품 뷰어 세부 정책 문서

(2026년 3월 11일 updated)

1. 목적

도서를 읽을 수 있는 화면을 뷰어라고 칭함. 사용자가 다양한 언어로 그림책을 열람하고, 뷰어 내에서 밝기 조절, 자동 스크롤, 녹음, 오디오 재생 등의 기능을 활용할 수 있도록, 작품 뷰어의 UI 구성 및 인터랙션 원칙을 정의한다.


2. 뷰어 아키텍처

2.1 ViewerBinding 구조

뷰어는 ViewerBinding 패턴을 통해 초기화되며, 각 서비스가 독립적으로 관리된다. bookId와 episodeId 조합으로 고유 태그를 생성하여 다중 뷰어 인스턴스를 지원한다.

서비스역할
ViewerDataService도서/에피소드 데이터 로딩 및 관리
ViewerScrollManager스크롤 위치 관리 및 진행률 계산
ViewerUIStateManagerUI 상태 관리 (메뉴 표시/숨김, 터치 이벤트 처리)
ViewerSettingsManager뷰어 설정 관리 (밝기, 자동 스크롤, 언어 등)
EpisodeRewardManager에피소드 완독 시 스티커 리워드 처리
SubscriptionGateManager비구독자 콘텐츠 접근 제한 관리

2.2 서비스 생명주기

  • 각 서비스는 뷰어 진입 시 Get.lazyPut()으로 등록되며, bookId-episodeId 태그로 고유 인스턴스 보장
  • 뷰어 종료 시 자동 해제 (fenix: false)
  • SubscriptionGateManagerViewerController와 연결되어 구독 상태에 따른 게이트 동작을 제어

3. 기본 구조

  • 뷰어 형식: 세로 스크롤 기반

  • 초기 언어 설정:

    • 구독자 및 비구독자 모두 처음으로 작품 뷰어에 진입할 때 독서 언어 설정 모달이 노출
    • 설정한 언어는 앱 전체에 공통 적용되며, 이후 작품에서도 그대로 유지됨
    • 언어 변경은 뷰어 내 [설정] 팝업 또는 [마이 > 앱 언어 설정]에서 가능함
  • 언어 스와이프 구조:

    • 설정된 언어 간에는 스와이프 제스처로 전환 가능
    • 화면 중앙: 주언어 (주언어 기본 or 유저가 가운데 카드에 설정한 언어)
    • 왼쪽/오른쪽: 부언어 1~2개 (작품이 해당 언어를 지원할 경우에만)
    • 제공되지 않는 언어는 dim 처리
    • 언어 재설정은 하단 설정 메뉴나 마이의 뷰어 설정에서 가능함.
  • 언어 상태 표시:

    • 언어를 2개 이상 설정한 사용자가 뷰어에 진입할 경우, 설정된 언어 목록을 안내하는 토스트 메시지가 노출됩니다.

4. 구독 게이트 정책

비구독자 또는 비로그인 사용자가 콘텐츠를 열람할 때, 읽기 진행률이 95% 이상에 도달하면 구독 유도 처리가 적용된다.

4.1 그라데이션 오버레이

  • 발동 조건: 비구독자/비로그인 상태에서 readingProgress >= 0.95 이고 하단 내비게이션이 표시 중일 때
  • 시각 효과: 하단 내비게이션 위에 그라데이션 오버레이 표시
    • 상단 → 하단 방향의 Linear Gradient
    • 상단 2%: 완전 투명 (rgba(255,255,255,0))
    • 하단 73%: 완전 불투명 (rgba(255,255,255,1))
  • 높이: 600px
  • 터치 이벤트: 오버레이 자체는 터치 이벤트를 통과시킴 (IgnorePointer)

4.2 하단 내비게이션 (비구독자)

비구독자에게도 구독자와 동일한 하단 메뉴 버튼을 제공하며, 구독 유도는 개별 기능 접근 시 처리된다.


5. 상단 영역 구성

  • 노출 방식: 스크롤과 무관하게 상단 고정 표시, 상/하단 15% 위치 탭하면 상/하 영역 동시 노출.

  • 구성:

    • 작품 상세로 가는 x 버튼
    • 작품명
    • 찜하기 버튼

6. 하단 영역 구성

  • 노출 방식:

    • 상단과 동일하게 화면 하단에 고정된 형태로 노출
    • 스크롤과 무관하게 하단 고정 표시, 상/하단 15% 위치 탭하면 상/하 영역 동시 노출.
  • 구성:

    1. 진행률 표시 바: 현재 읽기 진행률을 퍼센트(%)와 프로그레스 바로 표시. 드래그로 위치 이동 가능.

    2. 뷰어 설정 버튼: 클릭 시 2뎁스로 진입하며, 2뎁스는 창 크기가 변함

      • 구성 항목:
        • 자동 스크롤 ON/OFF 토글: ON 시 뷰어 우측에 속도 조절 버튼 노출
        • 밝기 조절: 수평 슬라이더로 밝기 조정
    3. 읽기/듣기 모드 토글 버튼: 읽기 모드와 듣기 모드 간 전환 (슬라이딩 애니메이션)

      • 읽기 모드: 기본 읽기 UI
      • 듣기 모드: 오디오 플레이리스트 다이얼로그 표시
    4. 녹음 버튼: 클릭 시 녹음 다이얼로그 표시

    5. 에피소드가 있는 작품은 에피소드 드롭다운 표시 (이전 화/다음 화 이동)

  • 위 메뉴들은 모두 하단 고정형 1뎁스 UI에서 진입하며, 각 항목 클릭 시 개별 2뎁스 화면으로 전환


7. 오디오/녹음/듣기 다이얼로그

뷰어 내에서 오버레이 형태로 표시되는 다이얼로그는 다음 3가지이며, 동시에 하나만 표시된다.

7.1 오디오 플레이리스트 다이얼로그 (AudioPlaylistDialog)

  • 진입: 듣기 모드 전환 시 표시
  • 구성: 오디오 트랙 목록, 재생 컨트롤, 플레이어 뷰
  • 배경: 반투명 딤 오버레이 (하단 내비게이션 영역 제외)
  • 닫기: 딤 영역 탭 시 읽기 모드로 전환 또는 듣기 모드 진입

7.2 녹음 다이얼로그 (RecordDialog)

  • 진입: 녹음 버튼 클릭 시 표시
  • 구성: 녹음/일시정지/재생/완료/나가기 버튼, 녹음 시간 표시, 파형 애니메이션
  • 제한: 녹음 모드에서는 전역 탭 오버레이 비활성화 (다이얼로그 버튼 우선)
  • 녹음 중 뷰어 제한: 세로 스크롤만 허용, 언어 전환 및 기타 설정 비활성화

7.3 듣기 다이얼로그 (AudioListeningDialog)

  • 진입: 플레이리스트에서 플레이어 뷰 활성화 후 딤 영역 탭 시
  • 구성: 미니 플레이어 형태로 오디오 재생 상태 유지
  • 동작: 듣기 모드 진입 시 자동 표시

7.4 뷰어 설정 다이얼로그 (ViewerSettingDialog)

  • 진입: 설정 버튼 클릭 시 표시
  • 구성: 자동 스크롤 토글, 밝기 조절 슬라이더
  • 배경: 반투명 딤 오버레이 (전체 화면)
  • 위치: 화면 하단에 고정

8. 녹음 모드

  • 진입 조건: 하단 녹음 버튼 클릭 시 (로그인/구독 상태는 컨트롤러에서 확인)

  • 화면 변경: 기존 하단 설정이 녹음 전용 상태창으로 전환 (RecordDialog)

  • 상태창 구성:

    • 녹음 / 일시정지 / 재생 / 녹음 완료 / 나가기(X) 버튼
    • 녹음 진행 시간 표시 (HH:MM)
    • 녹음 볼륨 및 진행상황 시각화 표시: 파형 애니메이션
    • 볼륨은 따로 두지 않고 적정 볼륨을 자동으로 설정하여 녹음함
  • 뷰어 제한: 세로 스크롤만 허용, 언어 전환 및 기타 설정은 비활성화

  • 오디오 처리: FFmpeg를 사용한 오디오 트리밍 및 노이즈 미터 지원

  • 저장 방식: 서버 업로드 방식으로 구현 완료 (S3 스토리지). Recording 모델을 통해 서버에 저장되며, 사용자/도서/에피소드/언어별로 관리된다.

  • Recording 모델 필드:

    필드타입설명
    userForeignKey녹음한 사용자
    bookForeignKey대상 도서
    episodeForeignKey (nullable)대상 에피소드
    language_codeCharField녹음 언어
    file_urlURLField녹음 파일 URL (S3)
    durationIntegerField녹음 길이 (초)
  • 저장 후: 안내 문구 출력 후 상태창이 플레이어 모드로 전환

  • 안내 문구 예시: "000님만의 오디오북이 완성되었습니다! 내 계정 > 나만의 오디오북에 저장 되었어요."

  • 저장된 녹음 관리: "내 계정 > 내가 녹음한 책"에서 조회/삭제 가능


9. 언어 미제공 시 예외 처리

  • 사용자가 설정한 언어가 해당 작품에서 제공되지 않는 경우:
    • 토스트: "이 작품은 00어를 제공하지 않습니다."
  • 초기 화면은 우선순위에 따라 우측 언어 → 좌측 언어 순으로 자동 지정 (제공되지 않는 언어는 dimmed 처리)

10. 기타 UI/UX 정책

  • 탭 전환 애니메이션: 부드러운 스와이프 전환 효과

  • 상단/하단 영역 자동 숨김:

    • 뷰어 첫 진입시 상 하단 영역 노출
    • 첫 진입 후 10초간 아무 동작없거나 / 스크롤, 스와이프시 상하단영역 숨김
    • UI가 숨겨진 상태에서는 화면 상단/하단 15% 영역을 터치했을 때 상단/하단 UI가 다시 노출됨
    • 전체 화면 아무 곳이나 터치 시에는 동작하지 않음 (아이들 몰입 방해 방지 목적)
    • 99% 이상 읽기 진행 시 터치 오버레이 비활성화 (하단 버튼 클릭 가능하도록)
  • 읽기 진행률 자동 저장:

    • 앱이 백그라운드로 전환될 때 자동 저장
    • 뷰어 닫기 시 마지막 스크롤 지점, 언어 상태, 밝기 설정 등 자동 저장
  • 태블릿/데스크톱 대응:

    • 넓은 화면에서는 콘텐츠 영역 너비 제한 적용 (ViewerLayoutConstants.contentWidth)
    • 하단 내비게이션 및 다이얼로그 모두 중앙 정렬로 표시