feat(vault): pick a notebook vault folder on first run
Some checks failed
CI / Windows build (push) Has been cancelled
Some checks failed
CI / Windows build (push) Has been cancelled
Phase 0 of the file-based storage plan (docs/plans/ 2026-06-24-file-based-storage.md). Foundation only — no editor or DB change yet. - VaultService (SharedPreferences): stores the vault root path, vaultRootValid() = path set AND directory exists. - VaultSetupScreen: first-run folder picker (file_picker, Windows). - main.dart gates HomeScreen behind a valid vault, re-prompting if the saved folder is gone. - Settings: a Vault section to change the folder. Editors still use SQLite; later phases move annotations into per-file sidecars under the vault. analyze clean, tests green.
This commit is contained in:
@@ -10,7 +10,9 @@ import 'editor/pdf/pen_capture_region.dart';
|
||||
import 'l10n/app_localizations.dart';
|
||||
import 'providers/settings_provider.dart';
|
||||
import 'screens/home_screen.dart';
|
||||
import 'screens/vault_setup_screen.dart';
|
||||
import 'services/database_service.dart';
|
||||
import 'services/vault_service.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
// Kind-aware binding (extends WidgetsFlutterBinding) must be the active
|
||||
@@ -64,7 +66,7 @@ class BadNoteApp extends ConsumerWidget {
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: const HomeScreen(),
|
||||
home: const VaultGate(),
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -78,3 +80,56 @@ class BadNoteApp extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Startup gate: shows [HomeScreen] only once a valid vault root folder has been
|
||||
/// chosen. If none is set — or the saved folder no longer exists — it shows
|
||||
/// [VaultSetupScreen] first (re-prompting on a missing folder rather than
|
||||
/// silently scattering data elsewhere). Phase 0: records the vault path only;
|
||||
/// editors still use SQLite.
|
||||
class VaultGate extends StatefulWidget {
|
||||
const VaultGate({super.key});
|
||||
|
||||
@override
|
||||
State<VaultGate> createState() => _VaultGateState();
|
||||
}
|
||||
|
||||
class _VaultGateState extends State<VaultGate> {
|
||||
VaultService? _vault;
|
||||
bool _valid = false;
|
||||
bool _hadStoredPath = false;
|
||||
bool _loading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_check();
|
||||
}
|
||||
|
||||
Future<void> _check() async {
|
||||
final vault = await VaultService.getInstance();
|
||||
final valid = await vault.vaultRootValid();
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_vault = vault;
|
||||
_valid = valid;
|
||||
// A stored-but-invalid path means the chosen folder went missing.
|
||||
_hadStoredPath = (vault.vaultRoot?.isNotEmpty ?? false);
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_loading) {
|
||||
return const Scaffold(
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
if (_valid) return const HomeScreen();
|
||||
return VaultSetupScreen(
|
||||
vaultService: _vault!,
|
||||
missing: _hadStoredPath,
|
||||
onVaultReady: () => setState(() => _valid = true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user