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:
parent
53ed5a6cd1
commit
f6b496dad7
@ -332,12 +332,25 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
}
|
||||
|
||||
Future<void> _pickFolder() async {
|
||||
try {
|
||||
final result = await FilePicker.platform.getDirectoryPath(
|
||||
dialogTitle: 'Select a folder containing Claude session files',
|
||||
);
|
||||
if (result != null) {
|
||||
_pathController.text = 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 {
|
||||
@ -393,15 +406,25 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
}
|
||||
|
||||
Future<void> _loadSingleFile() async {
|
||||
final home = _getRealHome() ?? '';
|
||||
try {
|
||||
final result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jsonl'],
|
||||
initialDirectory: '$home/.claude/projects',
|
||||
);
|
||||
if (result != null && result.files.single.path != null) {
|
||||
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 {
|
||||
@ -491,11 +514,13 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
// ─── Header with breadcrumb ──────────────────────────────
|
||||
|
||||
Widget _buildHeader(SessionProvider provider) {
|
||||
return Row(
|
||||
return Column(
|
||||
children: [
|
||||
// Row 1: breadcrumb + count
|
||||
Row(
|
||||
children: [
|
||||
const Icon(Icons.terminal, size: 24, color: AppColors.assistant),
|
||||
const SizedBox(width: 10),
|
||||
// Breadcrumb
|
||||
InkWell(
|
||||
onTap: () => setState(() => _selectedProject = null),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
@ -538,9 +563,16 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
: '${_projects.length} projects',
|
||||
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(
|
||||
controller: _pathController,
|
||||
focusNode: _pathFocusNode,
|
||||
@ -550,7 +582,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
fontFamily: 'JetBrains Mono',
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintText: '~/ .claude/projects',
|
||||
hintText: '~/.claude/projects',
|
||||
hintStyle: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textMuted,
|
||||
@ -585,15 +617,20 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
onSubmitted: (_) => _scanFromPathInput(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
SizedBox(
|
||||
height: 36,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _loadSingleFile,
|
||||
icon: const Icon(Icons.insert_drive_file_outlined, size: 14),
|
||||
label: const Text('Load'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.surfaceLight,
|
||||
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(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
side: const BorderSide(color: AppColors.surfaceBorder),
|
||||
@ -601,15 +638,20 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ElevatedButton.icon(
|
||||
SizedBox(
|
||||
height: 36,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _pickFolder,
|
||||
icon: const Icon(Icons.folder_open, size: 14),
|
||||
label: const Text('Browse'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.surfaceLight,
|
||||
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(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
side: const BorderSide(color: AppColors.surfaceBorder),
|
||||
@ -617,6 +659,9 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
textStyle: const TextStyle(fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user