Files
2026-07-08 19:02:14 +09:00

19 KiB

V2 ActionModal 전환 조사 및 구현

목적

V2 폴더/Group에서 사용하는 SodaDialog, popup, modal, sheet, toast 계열 표시 지점을 조사하고, 1차 전환 후보를 SodaV2ActionModal로 구현한다.

이번 문서는 조사, Phase 1 구현, Phase 2 판단, 검증 기록을 함께 다룬다.

조사 범위

  • 앱 코드: SodaLive/Sources/V2/**
  • V2에서 직접 호출하는 shared dialog/component:
    • SodaLive/Sources/Dialog/**
    • SodaLive/Sources/Report/**
    • SodaLive/Sources/Main/**
    • SodaLive/Sources/Content/Detail/**
    • SodaLive/Sources/Settings/Notification/**
    • SodaLive/Sources/Common/**
  • 제외: Pods/**, generated/**, build/**

조사 명령

  • rg -n --glob '*.swift' 'SodaDialog\(' 'SodaLive/Sources/V2'
  • rg -n --glob '*.swift' '(NotificationSettingsDialog\(|LivePaymentDialog\(|LiveRoomPasswordDialog\(|EventPopupDialogView\(|LiveRoomDonationDialogView\(|CommunityPostPurchaseDialog\(|CheersReportDialogView\(|CreatorCommunityReportView\(|CreatorCommunityMenuView\()' 'SodaLive/Sources/V2'
  • rg -n --glob '*.swift' '(CreatorChannelSortContextPopup\(|CreatorChannelActionPopup\(|CreatorChannelReplyDetailActionPopup\(|\.sodaToast\(|\.sheet\(|fullScreenCover\()' 'SodaLive/Sources/V2'
  • rg -n --glob '*.swift' 'SodaV2ActionModal\(' 'SodaLive/Sources/V2'
  • ast-grep pattern: SodaDialog($$$) on SodaLive/Sources/V2

기준 컴포넌트

SodaV2ActionModal

  • 정의: SodaLive/Sources/V2/Component/Modal/SodaV2ActionModal.swift
  • API:
    • title: String
    • message: String
    • button1: SodaV2ActionModalButton?
    • button2: SodaV2ActionModalButton?
    • onDimmedTap: () -> Void
  • 버튼 규칙:
    • button1은 primary action이며 Color.soda400로 표시된다.
    • button2는 secondary action이며 Color.white로 표시된다.
    • 렌더링 순서는 button2가 왼쪽, button1이 오른쪽이다.
    • 버튼이 1개만 유효하면 primary 스타일로 단독 표시된다.
    • label 또는 actionnil이면 해당 버튼은 표시되지 않는다.
  • UI 규칙:
    • dimmed background: Color.black.opacity(0.6)
    • modal width: 340
    • background: Color.gray900
    • corner radius: 14

1차 전환 후보: 높음

아래 4곳은 V2 내부에서 SodaDialog(...)를 직접 호출하며, 모두 확인/취소 또는 삭제/취소 형태의 action-only dialog다. SodaV2ActionModal 전환 우선순위가 높다.

SodaLive/Sources/V2/Main/MainView.swift

  • authConfirmDialog

    • 위치: MainView.swift:285
    • 전환 전: SodaDialog(title: I18n.Main.Auth.dialogTitle, desc: I18n.Main.Auth.liveEntryVerificationDescription, ...)
    • 상태: isShowAuthConfirmView
    • 동작: 본인 인증 안내 후 BootpayUI 인증 화면으로 이동하거나 취소 시 pendingAction을 비운다.
    • 적용 결과: title/message/인증 이동 primary/취소 secondary로 SodaV2ActionModal을 적용한다. dimmed tap은 V2 modal 동작에 맞춰 취소 흐름과 동일하게 처리한다.
  • leaveLiveNavigationDialog

    • 위치: MainView.swift:303
    • 전환 전: SodaDialog(title: I18n.Common.alertTitle, desc: I18n.LiveRoom.leaveLiveForNavigationDesc, ...)
    • 상태: isShowLeaveLiveNavigationDialog
    • 동작: 라이브 시청 중 외부 이동 시 confirmExternalNavigation() 또는 cancelExternalNavigation() 실행.
    • 적용 결과: 확인 primary, 취소 secondary로 SodaV2ActionModal을 적용한다. dimmed tap은 V2 modal 동작에 맞춰 취소 흐름과 동일하게 처리한다.

SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift

  • authConfirmDialog

    • 위치: CreatorChannelView.swift:329
    • 전환 전: SodaDialog(title: I18n.Chat.Auth.dialogTitle, desc: I18n.Chat.Auth.dialogDescription, ...)
    • 상태: isShowAuthConfirmView
    • 동작: 인증 안내 후 BootpayUI 인증 화면으로 이동하거나 취소 시 pendingAction을 비운다.
    • 적용 결과: MainView.authConfirmDialog와 같은 패턴으로 SodaV2ActionModal을 적용한다. dimmed tap은 V2 modal 동작에 맞춰 취소 흐름과 동일하게 처리한다.
  • community delete confirm

    • 위치: CreatorChannelView.swift:597
    • 전환 전: SodaDialog(title: I18n.Common.postDeleteTitle, desc: I18n.Common.confirmDeleteQuestion, ...)
    • 상태: communityViewModel.isShowDeleteConfirm
    • 동작: 확인 시 communityViewModel.deleteCommunityPost(creatorId:) 후 confirm 상태를 닫고, 취소 시 confirm 상태만 닫는다.
    • 적용 결과: 삭제 primary, 취소 secondary로 SodaV2ActionModal을 적용한다. dimmed tap은 V2 modal 동작에 맞춰 취소와 동일하게 isShowDeleteConfirm = false 처리한다.

이미 SodaV2ActionModal을 사용하는 기준 사례

구현 시 아래 사용처의 구조를 기준으로 삼는다.

  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift:347

    • fanTalkDeleteDialog
    • 팬Talk 삭제 확인.
    • 삭제 primary, 취소 secondary, dimmed tap dismiss 패턴.
  • SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift:54

    • 댓글 삭제 확인.
    • viewModel.confirmDeletedismissDeleteDialog 분리 패턴.
  • SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift:49

    • 답글/댓글 삭제 확인.
    • viewModel.confirmDeletedismissDeleteDialog 분리 패턴.
  • SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift:106

    • 작성 중 나가기 확인.
    • primary가 항상 destructive는 아니며, 강조할 CTA를 button1에 둔다.

별도 검토 후보

아래 항목은 V2에서 dialog/popup처럼 표시되지만, 입력 폼/도메인 UI/선택 UI가 포함되어 action-only SodaV2ActionModal로 단순 전환할 수 있는지 별도 판단이 필요하다.

  • SodaLive/Sources/V2/Main/MainView.swift:66

    • NotificationSettingsDialog()
    • 알림 설정 전용 dialog. 설정 UI 포함 여부 확인 필요.
  • SodaLive/Sources/V2/Main/MainView.swift:74

    • LivePaymentDialog(...)
    • 유료 라이브 결제/입장 확인. 시작/현재 시간 등 도메인 표시가 있어 단순 전환 전 UX 확인 필요.
  • SodaLive/Sources/V2/Main/MainView.swift:88

    • LiveRoomPasswordDialog(...)
    • 비밀번호 입력 field가 있어 action-only modal 전환 대상 가능성이 낮다.
  • SodaLive/Sources/V2/Main/MainView.swift:98

    • EventPopupDialogView(eventPopup:)
    • 이벤트 콘텐츠 팝업. 이미지/콘텐츠 표시 목적이면 SodaV2ActionModal과 목적이 다르다.
  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift:164

    • LiveRoomDonationDialogView(...)
    • 후원 금액, 메시지, 비밀후원 입력이 포함된 form dialog. 단순 전환 대상 가능성이 낮다.
  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift:591

    • CreatorCommunityReportView(...)
    • 신고 사유 선택 UI. 기존 report flow 재사용 범위로 유지할지 확인 필요.
  • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift:614

    • CommunityPostPurchaseDialog(...)
    • 유료 게시글 구매 확인. 금액 표시와 구매 action 중심이므로 V2 action modal 통일 여부를 UX 기준으로 결정한다.
  • SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationView.swift:114

    • CommunityPostPurchaseDialog(...)
    • 위와 동일한 구매 확인 dialog. CreatorChannelView 사용처와 함께 판단한다.
  • SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift:129

    • CheersReportDialogView(...)
    • 신고 사유 선택 dialog. 확인형 action modal과 목적이 다르므로 별도 검토.

전환 대상에서 제외할 가능성이 높은 항목

아래 항목은 이름에 popup/modal/presented가 포함되거나 overlay로 표시되지만, 확인형 dialog가 아니므로 이번 SodaV2ActionModal 전환 대상에서는 제외하는 것이 안전하다.

  • CreatorChannelSortContextPopup

    • 정의: SodaLive/Sources/V2/CreatorChannel/Components/CreatorChannelSortContextPopup.swift
    • 호출:
      • SodaLive/Sources/V2/Main/Content/All/MainContentAllView.swift:31
      • SodaLive/Sources/V2/CreatorChannel/Live/CreatorChannelLiveTabView.swift:77
      • SodaLive/Sources/V2/CreatorChannel/Audio/CreatorChannelAudioTabView.swift:87
      • SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesTabView.swift:66
    • 이유: 정렬 선택용 context menu다.
  • CreatorChannelActionPopup / CreatorChannelReplyDetailActionPopup

    • 정의:
      • SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift
      • SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailActionPopup.swift
    • 호출:
      • SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift:102
      • SodaLive/Sources/V2/CreatorChannel/Community/Detail/Components/CreatorChannelCommunityPostDetailCommentListView.swift:35
      • SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailFeedView.swift:48
    • 이유: 수정/삭제 action 선택용 anchored context popup이며, 실제 삭제 확인은 별도 modal이 담당한다.
  • .sheet(isPresented:)

    • SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift:23
    • 이유: 댓글 리스트 화면 표시용 sheet다.
  • .fullScreenCover(isPresented:)

    • SodaLive/Sources/V2/Main/MainView.swift:118
    • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift:190
    • 이유: BootpayUI 인증 화면 presentation이다.
  • .sodaToast(...)

    • 이유: isShowPopup 네이밍을 쓰는 ViewModel이 많지만 실제 UI는 toast다. action modal 전환 대상이 아니다.
    • 주요 호출 파일:
      • SodaLive/Sources/V2/Main/MainView.swift
      • SodaLive/Sources/V2/Main/Chat/MainChatView.swift
      • SodaLive/Sources/V2/Main/Content/Overview/ContentOverviewView.swift
      • SodaLive/Sources/V2/Main/Content/All/MainContentAllView.swift
      • SodaLive/Sources/V2/Main/Content/Ranking/MainContentRankingView.swift
      • SodaLive/Sources/V2/Main/Content/Recommendation/MainContentRecommendationView.swift
      • SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationView.swift
      • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
      • SodaLive/Sources/V2/CreatorChannel/Community/CreatorChannelCommunityTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/Community/Detail/CreatorChannelCommunityPostDetailView.swift
      • SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift
      • SodaLive/Sources/V2/CreatorChannel/Live/CreatorChannelLiveTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/Audio/CreatorChannelAudioTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/Series/CreatorChannelSeriesTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/Donation/CreatorChannelDonationTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift
      • SodaLive/Sources/V2/CreatorChannel/FanTalk/Write/CreatorChannelFanTalkWriteView.swift

구현 체크리스트

Phase 1: 1차 전환 후보 적용

  • Task 1.1: MainView.authConfirmDialogSodaV2ActionModal로 전환

    • 대상 파일: SodaLive/Sources/V2/Main/MainView.swift
    • 검증 기준: rg "authConfirmDialog|SodaV2ActionModal|SodaDialog" SodaLive/Sources/V2/Main/MainView.swift 실행 시 authConfirmDialogSodaV2ActionModal을 사용한다.
  • Task 1.2: MainView.leaveLiveNavigationDialogSodaV2ActionModal로 전환

    • 대상 파일: SodaLive/Sources/V2/Main/MainView.swift
    • 검증 기준: confirmExternalNavigation() / cancelExternalNavigation() 호출 흐름이 유지된다.
  • Task 1.3: CreatorChannelView.authConfirmDialogSodaV2ActionModal로 전환

    • 대상 파일: SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
    • 검증 기준: 인증 이동, 취소 시 pendingAction = nil 흐름이 유지된다.
  • Task 1.4: CreatorChannelView community delete confirm을 SodaV2ActionModal로 전환

    • 대상 파일: SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
    • 검증 기준: 삭제 확인, 취소, dimmed tap에서 communityViewModel.isShowDeleteConfirm 상태가 올바르게 닫힌다.

Phase 2: 별도 검토 후보 판단

  • Task 2.1: 구매/결제 dialog 전환 여부 결정

    • 대상 파일:
      • SodaLive/Sources/Dialog/LivePaymentDialog.swift
      • SodaLive/Sources/Dialog/CommunityPostPurchaseDialog.swift
      • SodaLive/Sources/V2/Main/MainView.swift
      • SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
      • SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationView.swift
    • 검증 기준: action-only modal로 대체 가능한지, 금액/시간 표시가 필요한지 결정이 문서에 남는다.
  • Task 2.2: 입력/신고/이벤트 dialog 제외 여부 결정

    • 대상 파일:
      • SodaLive/Sources/Dialog/LiveRoomPasswordDialog.swift
      • SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift
      • SodaLive/Sources/Report/CheersReportDialogView.swift
      • SodaLive/Sources/Main/EventPopupDialogView.swift
    • 검증 기준: SodaV2ActionModal 전환 제외 또는 별도 V2 컴포넌트화 여부가 문서에 남는다.

Phase 2 판단 결과

구매/결제 dialog

  • SodaLive/Sources/Dialog/CommunityPostPurchaseDialog.swift

    • 결정: 후속 구현에서 SodaV2ActionModal 전환 후보로 확정한다.
    • 이유: 제목, 설명, 취소, I18n.Dialog.CommunityPostPurchase.viewWithCans(can) 확인 CTA만 있는 action-only 구매 확인 dialog다.
    • V2 호출부: SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift, SodaLive/Sources/V2/Main/Home/Recommendation/MainHomeRecommendationView.swift
    • 후속 전환 방향: 구매 CTA를 button1, 취소를 button2, dimmed tap을 취소와 동일하게 isShowing = false 흐름으로 둔다.
  • SodaLive/Sources/Dialog/LivePaymentDialog.swift

    • 결정: 현재 shared dialog를 유지한다.
    • 이유: 기본 확인/취소 구조 외에 유료 라이브 시작 시간, 현재 시간, 추가 설명 영역을 조건부로 표시한다. 현재 SodaV2ActionModaltitle/message/buttons API로 단순 대체하면 시간 정보가 손실된다.
    • V2 호출부: SodaLive/Sources/V2/Main/MainView.swift
    • 후속 방향: V2 통일이 필요하면 SodaV2ActionModal 확장이 아니라 결제 전용 V2 dialog/component로 별도 설계한다.

입력/신고/이벤트 dialog

  • SodaLive/Sources/Dialog/LiveRoomPasswordDialog.swift

    • 결정: SodaV2ActionModal 전환 대상에서 제외한다.
    • 이유: 비밀번호 입력 field, 키보드 대응, 캔 수 조건부 CTA가 있는 input dialog다.
    • V2 호출부: SodaLive/Sources/V2/Main/MainView.swift
    • 후속 방향: 필요 시 V2 input modal로 별도 컴포넌트화한다.
  • SodaLive/Sources/Content/Detail/LiveRoomDonationDialogView.swift

    • 결정: SodaV2ActionModal 전환 대상에서 제외한다.
    • 이유: 후원 금액 입력, 단축 금액 버튼, 비밀 후원 토글, 메시지 입력, 충전 이동, validation toast를 포함한 복합 form/bottom-sheet 성격이다.
    • V2 호출부: SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift
    • 후속 방향: 필요 시 donation 전용 V2 modal/bottom-sheet로 별도 설계한다.
  • SodaLive/Sources/Report/CheersReportDialogView.swift

    • 결정: SodaV2ActionModal 전환 대상에서 제외한다.
    • 이유: 신고 사유 radio list 선택 상태가 필요한 selector dialog다.
    • V2 호출부: SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift
    • 후속 방향: 필요 시 V2 report selector 컴포넌트로 별도 설계한다.
  • SodaLive/Sources/Main/EventPopupDialogView.swift

    • 결정: SodaV2ActionModal 전환 대상에서 제외한다.
    • 이유: 원격 이미지 중심 콘텐츠 팝업이며 이미지 탭 상세 이동, 다시 보지 않기, 닫기 액션을 제공한다. 텍스트 확인형 action modal과 목적이 다르다.
    • V2 호출부: SodaLive/Sources/V2/Main/MainView.swift
    • 후속 방향: 필요 시 이벤트 팝업 전용 V2 component로 별도 설계한다.

검증 기록

  • 2026-07-08: rgast-grepSodaLive/Sources/V2 내부 SodaDialog(...) 직접 호출이 4곳임을 확인했다. 대상은 MainView.authConfirmDialog, MainView.leaveLiveNavigationDialog, CreatorChannelView.authConfirmDialog, CreatorChannelView community delete confirm이다.
  • 2026-07-08: rg 'SodaV2ActionModal\(' SodaLive/Sources/V2로 이미 적용된 기준 사례 4곳을 확인했다. 대상은 CreatorChannelView.fanTalkDeleteDialog, CreatorChannelCommunityPostDetailView, CreatorChannelReplyDetailView, CreatorChannelFanTalkWriteView다.
  • 2026-07-08: rg로 V2에서 호출하는 shared dialog 컴포넌트를 확인하고, 구매/결제/입력/신고/이벤트 dialog는 action-only modal 전환 여부를 별도 검토 후보로 분리했다.
  • 2026-07-08: isShowPopup 검색 결과의 대부분은 .sodaToast(...) 상태임을 확인해 SodaV2ActionModal 전환 대상에서 제외했다.
  • 2026-07-08: Phase 1 구현으로 MainView.authConfirmDialog, MainView.leaveLiveNavigationDialog, CreatorChannelView.authConfirmDialog, CreatorChannelView community delete confirm을 SodaV2ActionModal로 전환했다. 확인/취소 action은 유지하고, dimmed tap은 V2 modal 동작에 맞춰 각 취소 흐름과 동일하게 연결했다.
  • 2026-07-08: 전환 후 rg -n --glob '*.swift' 'SodaDialog\(' 'SodaLive/Sources/V2' 결과가 없어 V2 내부 직접 SodaDialog(...) 호출이 남지 않았음을 확인했다.
  • 2026-07-08: xcodebuild -workspace SodaLive.xcworkspace -scheme SodaLive-dev -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/SodaLiveDerivedData-SodaLiveDev CODE_SIGNING_ALLOWED=NO build 실행 결과 BUILD SUCCEEDED를 확인했다.
  • 2026-07-08: 기존 SodaDialog는 dimmed tap dismiss가 없지만, 이번 전환에서는 SodaV2ActionModal의 현재 UX에 맞춰 onDimmedTap을 각 취소 흐름과 동일하게 연결하는 것을 의도된 동작으로 정리했다.
  • 2026-07-08: Phase 2 구매/결제 dialog 검토 결과, CommunityPostPurchaseDialog는 action-only 구매 확인 dialog이므로 후속 SodaV2ActionModal 전환 후보로 확정하고, LivePaymentDialog는 시작/현재 시간 정보 박스와 추가 설명이 있어 shared dialog 유지로 결정했다.
  • 2026-07-08: Phase 2 입력/신고/이벤트 dialog 검토 결과, LiveRoomPasswordDialog, LiveRoomDonationDialogView, CheersReportDialogView, EventPopupDialogView는 입력/선택/이미지 콘텐츠 UI를 포함하므로 SodaV2ActionModal 전환 대상에서 제외하고 필요 시 별도 V2 컴포넌트화 대상으로 결정했다.