Setsuna is a cross-platform (Windows / macOS / Linux) desktop download manager built with Flutter, providing a user-friendly interface to manage local (built-in) and remote Aria2 instances.
- Published platforms: Windows (officially released)
- Unpublished platforms: macOS, Linux (not yet released)
- When making changes: Ensure compatibility across all three platforms, with special attention to Windows compatibility since it is the currently published target.
For Codex: All these commands need to be executed outside sandbox, or it will get stuck.
flutter run # Run in debug mode
flutter run -d <device-id> # Run with specific device
flutter build # Build for current platform (debug)
flutter build windows --release # Build Windows releaseflutter analyze # Run Flutter analyzer (recommended before committing)
flutter analyze --fix # Fix auto-fixable issues
flutter analyze --fatal-infos --fatal-warnings # Stricter rulesflutter test # Run all tests
flutter test test/add_task_options_test.dart # Run single test file
flutter test --name "testName" # Run specific test by name
flutter test --reporter expanded # Verbose output
flutter test --coverage # Run with code coverageflutter pub get # Get dependencies
flutter pub upgrade # Update dependencies
dart format . # Format codeOrder: dart: → package:flutter/ → package: → relative paths
// Good
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/aria2_instance.dart';
import '../../services/aria2_rpc_client.dart';- Use
flutter format .automatically - Max line length: 80 characters
- Use trailing commas
// Good
return Column(
children: [
ItemWidget(),
ItemWidget(),
],
);- Use strong typing - avoid
dynamic - Use
finalby default,varonly when reassignment needed
final List<DownloadTask> tasks = [];
void addTask(DownloadTask task) { ... }- Classes/Types: PascalCase (
class DownloadTask,enum DownloadStatus) - Functions/Variables: camelCase (
addTask(),downloadSpeed) - Files: snake_case (
download_task.dart) - Constants: SCREAMING_SNAKE_CASE for compile-time (
const DefaultPort = 6800)
- Use specific exception types
- Handle errors with try-catch, never silently swallow
try {
await client.connect();
} on ConnectionFailedException catch (e) {
log.e('Connection failed: ${e.message}');
rethrow;
} catch (e) {
log.e('Unexpected error: $e');
}- Use
async/awaitover raw Futures - Handle async errors with try-catch
- Extract widgets for reusability (>20 lines or repeated 2+ times)
- Use
constconstructors where possible - Keep
build()methods clean - delegate to helper methods
- Use
Providerfor dependency injection and state - Use
Consumerorcontext.watchfor reactive UI
- Use project's logging system (
lib/utils/logging.dart) - Repository-tracked log levels:
log.i(),log.w(),log.e() - Temporary debug logging may be added locally during development or troubleshooting, but it must be removed before the final commit/PR
- Don't log sensitive data (passwords, secrets)
- DRY - Don't Repeat Yourself
- YAGNI - Avoid over-engineering
- Single Responsibility - each class/method does one thing
- Prefer smaller files when practical - extract only when it clearly improves clarity
- Write tests for critical logic (RPC client, services)
| Task | Command |
|---|---|
| Run app | flutter run |
| Analyze | flutter analyze |
| Format | dart format . |
| Test one file | flutter test test/add_task_options_test.dart |
| Build Windows | flutter build windows --release |
- Prefer repository-tracked code and public upstream documentation as the source of truth.
assets/logo/app.svgis not referenced in Dart code but must be preserved (used by external tooling or packaging scripts).- When making changes, ensure compatibility across all three platforms (Windows, macOS, Linux), with special attention to Windows compatibility since it is the currently published target.