모바일 채팅 적응: 새로운 컴포넌트와 최적화
팀은 WebView 기반 애플리케이션에 완전한 모바일 반응성을 구현하여 로드를 줄이기 위해 기능을 간소화했습니다. 오디오 처리를 위한 RNNoiser 라이브러리 추가, 예약 메시지 기능, 확장된 서식으로 개선된 입력, 요청 지연 시간 감소, 데이터 저장 최적화를 진행했습니다. 모든 변경사항은 React Native와 WebView를 다루는 중급/고급 개발자를 대상으로 합니다.
터치 인터페이스를 위한 적응형 UI
MobileBottomNav를 개발했습니다 — 서버, 채팅, 칸반, 검색, 프로필의 다섯 개 탭으로 구성된 미니멀한 하단 네비게이션 바입니다. 이 컴포넌트는 상태를 가지지 않으며, 내부 로직이나 API 호출 없이 onViewChange를 통해 활성 뷰 ID만 전달합니다.
import { Icon } from '@shared/ui/Icon';
import { UserAvatar } from '@shared/ui/UserAvatar';
export function MobileBottomNav({
currentView,
onViewChange,
user
}) {
const tabs = [
{ id: 'general-chats', icon: 'groupChat', label: '서버' },
{ id: 'direct-chats', icon: 'chat', label: '채팅' },
{ id: 'chat-board', icon: 'board', label: '칸반' },
{ id: 'mobile-search', icon: 'search', label: '검색' },
{ id: 'profile', label: '프로필', isProfile: true },
];
return (
<nav className="mobile-bottom-nav">
{tabs.map(tab => (
<button
key={tab.id}
className={`mobile-bottom-nav-tab ${currentView === tab.id ? 'active' : ''}`}
onClick={() => onViewChange(tab.id)}
>
<span className="mobile-bottom-nav-icon">
{tab.isProfile ? (
<UserAvatar
avatar={user?.avatar}
userId={user?.user_id}
username={user?.username}
status={user?.status}
size={28}
showStatus={false}
className="mobile-bottom-nav-avatar"
/>
) : (
<Icon name={tab.icon} size={22} />
)}
</span>
<span className="mobile-bottom-nav-label">{tab.label}</span>
</button>
))}
</nav>
);
}
프로필 탭은 시각적 인식을 위해 아이콘 대신 UserAvatar를 사용합니다. 부모 컴포넌트가 수신된 ID를 기반으로 뷰 전환을 처리합니다.
최적화된 서버 목록
데스크톱 LeftMenu 대신 터치 상호작용을 위해 MobileServersList가 생성되었습니다. 왼쪽 패널은 Discord 스타일로 서버 아이콘을 표시하고, 오른쪽 패널은 선택된 서버의 주제를 보여줍니다. 이 컴포넌트는 비즈니스 로직(목록 로드, WebSocket 이벤트, 서버 생성)을 위해 useLeftMenu 훅을 재사용합니다. 이로 인해 코드 중복이 최소화되고 데스크톱 레이아웃에서 발생하는 렌더링 지연이 제거됩니다.
서버를 탭하면 전체 새로고침 없이 오른쪽의 주제가 업데이트됩니다. 주제를 탭하면 채팅이 열립니다.
확장된 서식으로 개선된 입력
입력은 Mattermost 형식에 맞게 조정되어 편집기 요소 래핑을 방지합니다. 기능은 다음과 같습니다:
- 굵게와 기울임: 표준 마크다운 서식.
- 코드 블록: 스니펫 삽입을 위한 구문 강조.
- PlantUML 다이어그램: 메시지 내에서 텍스트 마크업으로 UML 생성.
- 인용: >를 사용한 블록 강조.
- 링크: 하이퍼링크 삽입.
- 목록: 글머리 기호 또는 번호 매기기.
- 투표: 상호작용형 투표.
이를 통해 고급 개발자가 외부 도구 없이 기술 콘텐츠를 교환할 수 있습니다.
컨텍스트 메뉴와 제스처
하단 메뉴는 길게 탭하여 활성화됩니다 — isMobile 아래에 모바일 스타일을 적용한 기존 컴포넌트를 재사용합니다. 메시지 반응은 적응형 오버레이에서 열립니다. 오른쪽 메뉴는 모바일 장치를 위해 CSS와 조건부 로직으로 최적화되었습니다.
별도의 "예약됨" 섹션은 모든 계획된 메시지를 모아 빠른 스케줄러 개요를 제공합니다.
모바일 사용자 프로필
사용자 카드, 상태, 설정 섹션을 포함한 전용 MobileProfilePage 컴포넌트를 생성했습니다.
return (
<div className="mobile-profile-page">
<div className="mobile-profile-page-header">
<div className="mobile-profile-user-card">
<div className="mobile-profile-avatar">
{avatarUrl ? (
<img src={avatarUrl} alt={user.username} className="mobile-profile-avatar-img" />
) : (
<div className="mobile-profile-avatar-placeholder">{initials}</div>
)}
<span className={`status-icon ${user.status || 'offline'} mobile-profile-status"></span>
</div>
<div className="mobile-profile-info">
<div className="mobile-profile-username">{user.username}</div>
<div className="mobile-profile-handle">{user.handle || `@${user.username}`}</div>
</div>
</div>
</div>
<div className="mobile-profile-page-content">
<div className="mobile-profile-section">
<div className="mobile-profile-item" onClick={onOpenProfile}>
<span className="mobile-profile-item-icon"><Icon name="user" size={20} /></span>
<span className="mobile-profile-item-text">프로필 편집</span>
<span className="mobile-profile-item-arrow"><Icon name="chevronRight" size={16} /></span>
</div>
{/* 다른 항목들 유사하게 */}
</div>
{/* 상태 및 로그아웃 섹션 */}
</div>
</div>
);
각 항목은 콜백을 트리거하며, 컴포넌트는 모달이나 네비게이션을 관리하지 않습니다.
추가 개선사항
- RNNoiser: 음성 메시지와 통화의 잡음을 줄이기 위해 통합.
- 지연 시간: 캐싱과 일괄 처리를 통해 요청 최적화.
- 데이터 저장: 모바일 메모리 제약을 고려하여 완전히 재구성.
이러한 변경사항은 기능을 저하시키지 않으면서 저사양 장치에서의 성능을 보장합니다.
핵심 요약
- 터치 인터페이스를 위한 별도 컴포넌트로 완전한 WebView 반응성.
- 중복 없이 훅을 통한 비즈니스 로직 재사용.
- 기술 채팅을 위한 PlantUML과 투표가 포함된 확장된 입력.
- 계획 편의를 위한 전용 섹션의 예약 메시지.
- 예측 가능한 렌더링을 위한 UI 컴포넌트의 상태 비저장 접근.
— Editorial Team
아직 댓글이 없습니다.