claude_session_viewer/lib/services/native_picker.dart
Mathias Beaulieu-Duncan 780ef9378f feat: custom native file picker showing hidden files/folders
Replaced file_picker's Load/Browse with a custom NativePickerRegistrar
Swift plugin that opens NSOpenPanel with showsHiddenFiles = true.
The file_picker package hardcodes this to false, making hidden folders
like ~/.claude invisible in its dialogs.

Changes:
- New NativePickerRegistrar.swift: custom NSOpenPanel with hidden files
- New NativePicker Dart service using method channel
- Browse: only shows folders (canChooseFiles=false), hidden visible
- Load: only shows .jsonl files, hidden folders visible
- Registered via AppDelegate.applicationDidFinishLaunching
- Removed file_picker dependency from home_screen imports
- Fixed all info-level lint issues (super params, null-aware, doc comment)
- Signed, notarized, stapled DMG
2026-04-07 14:32:06 -04:00

42 lines
1.4 KiB
Dart

import 'package:flutter/services.dart';
/// Native file picker that shows hidden files/folders on macOS.
/// Uses a custom method channel to NSOpenPanel with showsHiddenFiles = true,
/// which the file_picker package hardcodes to false.
class NativePicker {
static const _channel = MethodChannel('com.svrnty.native_picker');
/// Opens a folder picker that shows hidden directories.
/// Returns the selected folder path, or null if cancelled.
static Future<String?> getDirectoryPath({String? initialDirectory}) async {
try {
return _channel.invokeMethod<String?>('getDirectoryPath', {
'initialDirectory': initialDirectory,
});
} on PlatformException catch (e) {
throw Exception('Native picker error: ${e.message}');
}
}
/// Opens a file picker that shows hidden files, filtered to specific extensions.
/// Returns the selected file path, or null if cancelled.
static Future<String?> pickFile({
List<String> allowedExtensions = const [],
String? initialDirectory,
}) async {
try {
final result = await _channel.invokeMethod<List?>('pickFiles', {
'allowMultiple': false,
'allowedExtensions': allowedExtensions,
'initialDirectory': initialDirectory,
});
if (result != null && result.isNotEmpty) {
return result.first as String;
}
return null;
} on PlatformException catch (e) {
throw Exception('Native picker error: ${e.message}');
}
}
}