import 'dart:io'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/note.dart'; import '../services/vault_service.dart'; import 'document_provider.dart' show vaultServiceProvider; /// The home-screen note list is now sourced from a VAULT SCAN of standalone /// (free-ink) notebook folders — each a folder holding a `notebook.badnote.json` /// and NO importable source file — NOT the SQLite `notes` table. The sidecar /// that lives in the folder is the source of truth ("跟着文件走"). /// /// Each scanned note is adapted into the existing [Note] model the home screen /// already renders: `id` = the synthetic note path (`/notebook`, also a /// stable id), `title`, `updatedAt` = the sidecar mtime. Strokes are NOT loaded /// here — they are hydrated lazily by the editor from the sidecar, so the list /// stays cheap (one directory listing). Home tiles that show a stroke count will /// therefore read 0 until the note is opened; the count is no longer cached. final noteListProvider = AsyncNotifierProvider>( NoteListNotifier.new, ); class NoteListNotifier extends AsyncNotifier> { Future get _vault => ref.read(vaultServiceProvider.future); @override Future> build() async { return _scan(); } Future> _scan() async { final vault = await _vault; final notes = await vault.scanNotes(); return notes.map(_toNote).toList(); } /// Adapt a scanned [VaultNote] into the [Note] shape the home tiles render. /// `id` is the synthetic note path so opening it re-keys the right sidecar. Note _toNote(VaultNote n) => Note( id: n.notePath, title: n.title, createdAt: n.modified, updatedAt: n.modified, ); /// Re-scan the vault and publish the result. Used by pull-to-refresh and /// after a note is created or edited. Future loadNotes() async { state = const AsyncLoading(); state = await AsyncValue.guard(_scan); } /// Create an empty standalone notebook folder with [title] and return the /// adapted [Note] (whose `id` is the synthetic note path). The home screen /// opens the editor on it; persistence flows through the sidecar. Future createNote({String title = 'Untitled'}) async { final vault = await _vault; final notePath = await vault.createEmptyNotebook(title); final now = DateTime.now(); final note = Note( id: notePath, title: title, createdAt: now, updatedAt: now, ); state = AsyncData([note, ...state.value ?? []]); return note; } /// Delete a note by removing its notebook folder (the sidecar travels with /// it). [id] is the synthetic note path `/notebook`. Future deleteNote(String id) async { final folder = Directory(File(id).parent.path); if (await folder.exists()) { await folder.delete(recursive: true); } final current = state.value ?? []; state = AsyncData(current.where((n) => n.id != id).toList()); } }