fix: two-row header layout, flexible path input, button error handling

- Split header into two rows: breadcrumb + count on top, path/buttons below
- Path input is now flexible (fills available width) instead of fixed 320px
- Fixes Row overflow on narrow windows
- Load/Browse buttons now same height (36px) as path input
- Added try/catch with snackbar error feedback for Load and Browse
- Removed initialDirectory from file picker (could fail in non-sandbox)
- Browse also updates the path input field when a folder is selected
- Signed, notarized, stapled DMG
This commit is contained in:
Mathias Beaulieu-Duncan 2026-04-07 14:01:04 -04:00
parent 53ed5a6cd1
commit f6b496dad7

View File

@ -332,12 +332,25 @@ class _HomeScreenState extends State<HomeScreen> {
} }
Future<void> _pickFolder() async { Future<void> _pickFolder() async {
try {
final result = await FilePicker.platform.getDirectoryPath( final result = await FilePicker.platform.getDirectoryPath(
dialogTitle: 'Select a folder containing Claude session files', dialogTitle: 'Select a folder containing Claude session files',
); );
if (result != null) { if (result != null) {
_pathController.text = result;
await _scanFolder(result); await _scanFolder(result);
} }
} catch (e) {
debugPrint('[Browse] Error: $e');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Could not open folder picker: $e'),
backgroundColor: AppColors.error,
),
);
}
}
} }
Future<void> _scanFolder(String folderPath) async { Future<void> _scanFolder(String folderPath) async {
@ -393,15 +406,25 @@ class _HomeScreenState extends State<HomeScreen> {
} }
Future<void> _loadSingleFile() async { Future<void> _loadSingleFile() async {
final home = _getRealHome() ?? ''; try {
final result = await FilePicker.platform.pickFiles( final result = await FilePicker.platform.pickFiles(
type: FileType.custom, type: FileType.custom,
allowedExtensions: ['jsonl'], allowedExtensions: ['jsonl'],
initialDirectory: '$home/.claude/projects',
); );
if (result != null && result.files.single.path != null) { if (result != null && result.files.single.path != null) {
await _loadFile(result.files.single.path!); await _loadFile(result.files.single.path!);
} }
} catch (e) {
debugPrint('[Load] Error: $e');
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Could not open file picker: $e'),
backgroundColor: AppColors.error,
),
);
}
}
} }
Future<void> _loadFile(String path) async { Future<void> _loadFile(String path) async {
@ -491,11 +514,13 @@ class _HomeScreenState extends State<HomeScreen> {
// Header with breadcrumb // Header with breadcrumb
Widget _buildHeader(SessionProvider provider) { Widget _buildHeader(SessionProvider provider) {
return Row( return Column(
children: [
// Row 1: breadcrumb + count
Row(
children: [ children: [
const Icon(Icons.terminal, size: 24, color: AppColors.assistant), const Icon(Icons.terminal, size: 24, color: AppColors.assistant),
const SizedBox(width: 10), const SizedBox(width: 10),
// Breadcrumb
InkWell( InkWell(
onTap: () => setState(() => _selectedProject = null), onTap: () => setState(() => _selectedProject = null),
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
@ -538,9 +563,16 @@ class _HomeScreenState extends State<HomeScreen> {
: '${_projects.length} projects', : '${_projects.length} projects',
style: const TextStyle(fontSize: 12, color: AppColors.textMuted), style: const TextStyle(fontSize: 12, color: AppColors.textMuted),
), ),
// Path input field ],
SizedBox( ),
width: 320, const SizedBox(height: 12),
// Row 2: path input + Load + Browse
Row(
children: [
// Path input field flexible to fill available space
Expanded(
child: SizedBox(
height: 36,
child: TextField( child: TextField(
controller: _pathController, controller: _pathController,
focusNode: _pathFocusNode, focusNode: _pathFocusNode,
@ -585,15 +617,20 @@ class _HomeScreenState extends State<HomeScreen> {
onSubmitted: (_) => _scanFromPathInput(), onSubmitted: (_) => _scanFromPathInput(),
), ),
), ),
),
const SizedBox(width: 8), const SizedBox(width: 8),
ElevatedButton.icon( SizedBox(
height: 36,
child: ElevatedButton.icon(
onPressed: _loadSingleFile, onPressed: _loadSingleFile,
icon: const Icon(Icons.insert_drive_file_outlined, size: 14), icon: const Icon(Icons.insert_drive_file_outlined, size: 14),
label: const Text('Load'), label: const Text('Load'),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppColors.surfaceLight, backgroundColor: AppColors.surfaceLight,
foregroundColor: AppColors.textPrimary, foregroundColor: AppColors.textPrimary,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 0),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
side: const BorderSide(color: AppColors.surfaceBorder), side: const BorderSide(color: AppColors.surfaceBorder),
@ -601,15 +638,20 @@ class _HomeScreenState extends State<HomeScreen> {
textStyle: const TextStyle(fontSize: 12), textStyle: const TextStyle(fontSize: 12),
), ),
), ),
),
const SizedBox(width: 8), const SizedBox(width: 8),
ElevatedButton.icon( SizedBox(
height: 36,
child: ElevatedButton.icon(
onPressed: _pickFolder, onPressed: _pickFolder,
icon: const Icon(Icons.folder_open, size: 14), icon: const Icon(Icons.folder_open, size: 14),
label: const Text('Browse'), label: const Text('Browse'),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppColors.surfaceLight, backgroundColor: AppColors.surfaceLight,
foregroundColor: AppColors.textPrimary, foregroundColor: AppColors.textPrimary,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 0),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
side: const BorderSide(color: AppColors.surfaceBorder), side: const BorderSide(color: AppColors.surfaceBorder),
@ -617,6 +659,9 @@ class _HomeScreenState extends State<HomeScreen> {
textStyle: const TextStyle(fontSize: 12), textStyle: const TextStyle(fontSize: 12),
), ),
), ),
),
],
),
], ],
); );
} }