Imported from mtravascio/pdf_splitter (
AGENTS.md). Install upstream withnpx skills add mtravascio/pdf_splitter. Copyright stays with the author.
AGENTS.md - PDF Splitter Project
Project Overview
This is a Flutter desktop application that splits PDF files based on names found in a CSV file. It uses the GetX state management library and supports Windows, macOS, and Linux.
Build/Lint/Test Commands
Flutter Commands
# Run the application
flutter run
# Build for release
flutter build
# Analyze code for errors and warnings
flutter analyze
# Run all tests
flutter test
# Run a single test file
flutter test test/widget_test.dart
# Run tests with a specific name pattern
flutter test --name "Counter"
# Run tests in a specific directory
flutter test test/
Platform-Specific Builds
# Build for macOS
flutter build macos
# Build for Linux
flutter build linux
# Build for Windows
flutter build windows
Code Style Guidelines
Analysis Options
The project uses flutter_lints package with default settings. Run flutter analyze to check for issues.
Dart Style Rules
- Use
dart formatto format code before committing - Enable
prefer_single_quotesinanalysis_options.yamlfor cleaner code - Avoid
print()statements in production code; use theLogControllerinstead
Imports
Organize imports in the following order:
- Dart SDK imports (
dart:io,dart:async) - Flutter/Dart package imports (
package:flutter/...,package:csv/...) - Local package imports (
package:pdf_splitter/...) - Relative imports (last resort)
// Correct import order
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'package:pdf_splitter/logger_controller.dart';
Naming Conventions
- Classes: PascalCase (
PdfSplitterController,LogController) - Variables/Methods: camelCase (
csvFilePath,pickCsvFile(),isProcessing) - Private members: leading underscore (
_message,_initialize()) - Constants: camelCase or SCREAMING_SNAKE_CASE based on context
- Rx Variables (GetX): use
.obssuffix pattern
Types
- Use explicit types rather than
varwhen the type is not obvious - Prefer
String,int,bool,doubleover dynamic types - Use
latefor deferred initialization when appropriate - Use
dynamicsparingly and only when necessary
GetX Patterns
- Controllers extend
GetxControllerand use.obsfor reactive state - Use
Obx()widget to rebuild UI on reactive changes - Use
Rx<T>for nullable reactive types - Initialize controllers with
Get.put(ControllerName())
// Reactive state example
var isProcessing = false.obs;
String get message => _message.value;
// Controller initialization
final PdfSplitterController controller = Get.put(PdfSplitterController());
Error Handling
- Use
try-catchblocks for async operations - Provide meaningful error messages
- Use
appError()method from controller for logging errors - Handle null-safety explicitly with
?and??operators
try {
final result = await someAsyncOperation();
} catch (e) {
appError('Operation failed: $e');
message = 'Error: $e';
}
Widget Building
- Keep
build()methods focused and readable - Extract complex widgets into separate methods or classes
- Use
constconstructors where possible - Prefer
Obx()for reactive UI updates
File Structure
lib/
├── main.dart # App entry point and PdfSplitterController
├── logger_controller.dart # Logging functionality
test/
├── widget_test.dart # Widget tests
assets/
├── send_mail.vbs # Windows email script
├── send_mail.sh # Linux/macOS email script
Architecture Notes
State Management
The app uses GetX for:
- State management (reactive
.obsvariables) - Dependency injection (
Get.put()) - Logging (via
LogController)
Key Classes
MyApp: Root MaterialApp widgetPdfSplitterController: Main business logic controllerPdfSplitter: Main UI widgetLogController: Centralized logging
CSV Format
Expected CSV columns:
- Column 0: Page number (integer)
- Column 1: Name
- Column 2: Description (optional)
- Column 3: Directory (optional)
- Column 4: Subdirectory (optional)
- Column 5: Email address (optional, format:
from: email@example.com)
Logging
Use the LogController methods for all logging:
logInfo()- General information messageslogDebug()- Debug messageslogError()- Error messages
Never commit code with print() statements in production paths.
Testing Notes
- Widget tests use
WidgetTesterfromflutter_test - Use
testWidgets()for integration tests - Use
expect()for assertions