앱이 말을 걸다 — 대화형 가이드 모드
태스크 작성을 대화처럼 안내하는 가이드 모드 구현기입니다. fecit 아이콘이 말풍선으로 질문하고, 격려하고, 마무리까지.
앱이 말을 걸다
빈 화면 앞에서
Fecit에서 태스크를 만들면 타이틀, 설명, 현재 상황, 기대, 난관, 작전… 채울 수 있는 필드가 많습니다. Minimal to Maximal 철학에 따라 처음엔 타이틀만 보이고, 나머지는 사용자가 원할 때 펼치는 구조입니다.
하지만 처음 쓰는 사람에게는 이 구조 자체가 낯설 수 있습니다. “현재 상황이요? 여기에 뭘 쓰라는 거죠?” 각 필드가 무슨 역할인지, 어떤 순서로 채우면 좋은지 안내가 필요했습니다.
도움말 페이지를 만드는 건 쉽지만, 아무도 안 읽습니다. 실제로 필드를 채우는 그 순간에, 맥락에 맞는 안내가 나와야 합니다.
가이드 모드라는 아이디어
태스크 편집 화면 상단에 작은 가이드 바를 띄우기로 했습니다. 5단계로 나누어 하나씩 질문합니다:
- 이루고 싶은 것이 무엇인가요? → 타이틀
- 현재 상황은 어떤가요? → Target
- 어떤 결과를 기대하시나요? → Expectation
- 어떤 난관을 극복해야 하나요? → Obstacle
- 어떻게 해결하실 건가요? → 작전(Description)
단계를 넘길 때마다 해당 필드에 자동으로 포커스가 이동하고, 화면이 스크롤됩니다. 사용자는 질문에 답하듯 내용을 채워나갑니다.
”좋아요!”
단순히 질문만 던지면 설문지 같습니다. 뭔가가 “말하고 있는” 느낌을 주고 싶었습니다.
단계를 넘길 때 바로 다음 질문으로 가지 않고, 격려 메시지를 먼저 보여줍니다. “좋아요!”, “훌륭해요!”, “바로 그거예요!” 같은 짧은 한마디. 1초 동안 보여준 뒤 다음 질문으로 전환합니다.
10가지 메시지 중 랜덤으로 나오되, 같은 말이 연속으로 나오지 않도록 했습니다. 작은 디테일이지만 기계적인 느낌을 줄여줍니다.
마지막 단계를 끝내면 “준비 완료! 이제 시작해봐요!” 하고 마무리 인사를 한 뒤 가이드가 사라집니다.
fecit 아이콘이 말을 건다
격려 메시지만으로는 “누가” 말하는 건지 모릅니다. fecit 아이콘을 가이드 바 왼쪽에 고정하고, 옆에 말풍선을 달았습니다. 꼬리가 아이콘을 가리키는 형태입니다.
아이콘의 위치가 중요했습니다. 내용에 따라 움직이면 장식처럼 보이고, 버튼 위치에 두면 누를 수 있을 것 같습니다. 결국 왼쪽에 고정하되 닫기 버튼과 분리해서, 아이콘은 “화자”이고 말풍선은 “대사”라는 관계가 명확하도록 했습니다.
질문할 때도, 격려할 때도, 마무리할 때도 같은 아이콘이 같은 자리에서 말합니다. 일관된 존재감.
키보드와의 씨름
구현에서 가장 까다로운 부분은 키보드 핸들링이었습니다.
포커스 이동: 가이드 바의 “다음” 버튼을 누르면 현재 입력 필드가 blur되면서 키보드가 내려갑니다. 그 상태에서 다음 필드에 포커스를 주면 키보드가 다시 올라옵니다. 이 전환이 자연스러워야 했습니다.
키보드 dismiss로 진행: 버튼을 누르는 것 외에도, 키보드를 내리면 자동으로 다음 단계로 넘어가도록 했습니다. keyboardDidHide 이벤트를 감지해서 처리합니다. 단, 가이드가 끝날 때 Keyboard.dismiss()를 호출하면 이 리스너가 다시 발동하는 문제가 있어서, guideModeRef라는 동기 플래그로 제어합니다.
커스텀 네이티브 모듈: React Native의 Keyboard.dismiss()는 표준 TextInput만 대상으로 합니다. Fecit은 ChipTextInput과 RichDescriptionInput이라는 커스텀 Expo 모듈을 쓰기 때문에, iOS의 UIApplication.sendAction(resignFirstResponder) 를 호출하는 별도 함수가 필요했습니다.
스크롤 위치 맞추기
각 필드로 포커스가 이동할 때, 해당 필드가 화면에 보여야 합니다. DraggableFlatList를 사용하고 있어서 scrollToOffset이 동작하지 않았고, 내부 ScrollView의 getNativeScrollRef().scrollTo()를 직접 호출해야 했습니다.
필드 위치는 onLayout으로 추적합니다. 분석 섹션(Target, Expectation, Obstacle) 내부의 필드들은 중첩된 View 안에 있어서, 부모 섹션의 offset과 필드 자체의 offset을 합산해야 정확한 콘텐츠 Y를 구할 수 있습니다.
포커스와 스크롤의 타이밍도 중요합니다. 포커스를 먼저 주고, 키보드가 올라온 뒤에 스크롤합니다. 키보드가 올라오면 레이아웃이 바뀌기 때문에, 400ms 정도 지연시킨 뒤에 스크롤해야 정확한 위치로 이동합니다.
첫 단계
지금의 가이드 모드는 첫 단계입니다. 질문하고, 격려하고, 마무리하는 기본 흐름만 있습니다.
앞으로 발전시키고 싶은 방향은 많습니다. 사용자가 쓴 내용에 따라 다른 반응을 보여주거나, 처음 쓰는 사용자에게만 자동으로 가이드를 띄우거나, 각 필드에 맞는 예시를 제안하거나. 가이드가 단순한 튜토리얼이 아니라, 태스크를 더 잘 정리하도록 돕는 대화 상대가 되는 것이 목표입니다.
fecit 아이콘이 말을 거는 순간, 빈 화면이 조금 덜 막막해지길 바랍니다.