[hotfix] #342 v0.4.2 — ChatScreen SafeArea + LLM 에러 진단 노출

Fix
- ChatScreen body 를 SafeArea(top: false) 로 감쌈. Android edge-to-edge
  모드에서 시스템 nav bar 가 입력창을 덮던 문제 해결.

Dev (#342)
- userTurn catch 블록이 e.toString() + stack trace 를 error 상태에 저장.
- 빨간 에러 컨테이너를 SingleChildScrollView + SelectableText (monospace)
  + 최대 화면 1/3 높이 제약. 스크롤 + 복사 가능. release 빌드에서도
  full stack 노출 (#342 종료 후 follow-up 으로 좁힘).

테스트: chat_session_controller_test 8/8 통과.
APK: app-release.apk 301.0MB SHA 02a5d1c8.

Refs #342
This commit is contained in:
2026-06-15 14:30:21 +09:00
parent 94a9cd474b
commit 3b8ea95aa6
4 changed files with 38 additions and 11 deletions

View File

@@ -3,6 +3,14 @@
본 프로젝트의 모든 의미있는 변경은 본 파일에 기록한다.
형식: [Keep a Changelog](https://keepachangelog.com/) · 버전: [SemVer](https://semver.org/).
## [0.4.2] — 2026-06-15 (hotfix, dev)
### Fixed (Redmine #342)
- **ChatScreen 하단 잘림** — Android edge-to-edge 모드에서 시스템 nav bar (3-button / gesture handle) 가 입력창을 덮던 문제. `Scaffold.body``SafeArea(top: false, …)` 로 감쌈. AppBar 가 이미 top inset 처리하므로 top 만 false.
### Dev
- **LLM 실패 빨간 배너에 full message + stack trace** — 단말 진단을 위해 release 빌드에서도 노출. `LLM 응답 실패: <Type>\n<message>\n--- STACK ---\n<stack>` 형식. SelectableText + monospace + 최대 화면 1/3 높이 + scroll. 사용자 친화 메시지로 좁히는 작업은 #342 종료 후 follow-up.
## [0.4.1] — 2026-06-15
### Added — ChatScreen LLM warm-up (Redmine #311, follow-up of #260)

View File

@@ -206,12 +206,16 @@ class ChatSessionController extends StateNotifier<ChatSessionState> {
clearStreamingText: true,
error: '도구 호출 루프가 너무 길어 중단했습니다.',
);
} catch (e) {
} catch (e, st) {
if (!mounted) return;
// 개발 단계 (#342) — 실 단말 진단을 위해 release 빌드에서도 full
// message + stack 노출. 사용자 친화 메시지로 다시 좁히는 작업은
// #342 종료 후 follow-up.
final detail = 'LLM 응답 실패: ${e.runtimeType}\n$e\n\n--- STACK ---\n$st';
state = state.copyWith(
isStreaming: false,
clearStreamingText: true,
error: 'LLM 응답 실패: ${e.runtimeType}',
error: detail,
);
}
}

View File

@@ -76,10 +76,16 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
),
],
),
body: depsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('초기화 실패: $e')),
data: (_) => _buildBody(context),
// Android edge-to-edge: 시스템 nav bar (3-button / gesture handle) 가
// 입력창을 가리지 않도록 SafeArea 로 감싼다. AppBar 가 이미 top inset
// 을 처리하므로 top 만 false.
body: SafeArea(
top: false,
child: depsAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Center(child: Text('초기화 실패: $e')),
data: (_) => _buildBody(context),
),
),
);
}
@@ -105,14 +111,23 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
children: [
if (warmup is ChatWarmupFailed) _WarmupErrorBanner(warmup: warmup),
if (state.error != null)
// #342 dev — 단말에서 원인 진단을 위해 stack 까지 노출되는 케이스를
// 위해 multi-line + scrollable + selectable. 높이는 화면의 1/3 까지만.
Container(
width: double.infinity,
color: theme.colorScheme.errorContainer,
padding: const EdgeInsets.all(12),
child: Text(
state.error!,
style: TextStyle(
color: theme.colorScheme.onErrorContainer,
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 3,
),
child: SingleChildScrollView(
child: SelectableText(
state.error!,
style: TextStyle(
color: theme.colorScheme.onErrorContainer,
fontFamily: 'monospace',
fontSize: 12,
),
),
),
),

View File

@@ -1,7 +1,7 @@
name: life_helper
description: "Huberman + Atomic Habits + Tiny Habits + If-Then. Local-first habit/checklist/todo."
publish_to: 'none'
version: 0.4.1+5
version: 0.4.2+6
environment:
sdk: ^3.12.2