mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-07-04 15:23:06 +02:00
Add the complete annotations feature for marking and annotating script text: Core models (horatio_core): - TextMark, LineNote, AnnotationSnapshot, MarkType, NoteCategory - Script.id field + UUID generation in text_parser Database layer (horatio_app): - Drift tables: text_marks, line_notes, annotation_snapshots - AppDatabase with AnnotationDao (full CRUD + streams + bulk replace) State management: - AnnotationCubit: mark/note CRUD, line selection, editing context - AnnotationHistoryCubit: snapshot save/restore with stream updates UI components: - MarkOverlay: colored span rendering for text marks - NoteIndicator: per-line note count badge - MarkTypePicker: 6-type ActionChip selector - NoteEditorSheet: category dropdown + text field bottom sheet - AnnotationEditorScreen: full editor with long-press marks + note editing - AnnotationHistoryScreen: snapshot timeline with restore dialog Wiring: - main.dart: async DB init with path_provider - app.dart: RepositoryProvider<AnnotationDao> - router.dart: /annotations + /annotation-history routes - role_selection_screen: Annotate Script option - run.sh: app_codegen step + coverage filtering for generated code 352 tests (105 core + 247 app), 100% branch coverage, zero dead code.
131 lines
4.0 KiB
Dart
131 lines
4.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:horatio_app/screens/annotation_editor_screen.dart';
|
|
import 'package:horatio_app/screens/annotation_history_screen.dart';
|
|
import 'package:horatio_app/screens/home_screen.dart';
|
|
import 'package:horatio_app/screens/import_screen.dart';
|
|
import 'package:horatio_app/screens/rehearsal_screen.dart';
|
|
import 'package:horatio_app/screens/role_selection_screen.dart';
|
|
import 'package:horatio_app/screens/schedule_screen.dart';
|
|
import 'package:horatio_app/screens/srs_review_screen.dart';
|
|
import 'package:horatio_core/horatio_core.dart';
|
|
|
|
/// Route paths.
|
|
abstract final class RoutePaths {
|
|
/// Home / script library.
|
|
static const String home = '/';
|
|
|
|
/// Import a new script.
|
|
static const String import_ = '/import';
|
|
|
|
/// Select a role after importing a script.
|
|
static const String roleSelection = '/role-selection';
|
|
|
|
/// View memorization schedule.
|
|
static const String schedule = '/schedule';
|
|
|
|
/// Interactive rehearsal mode.
|
|
static const String rehearsal = '/rehearsal';
|
|
|
|
/// SRS flashcard review.
|
|
static const String srsReview = '/srs-review';
|
|
|
|
/// Annotation editor.
|
|
static const String annotations = '/annotations';
|
|
|
|
/// Annotation history.
|
|
static const String annotationHistory = '/annotation-history';
|
|
}
|
|
|
|
/// Application router configuration.
|
|
final GoRouter appRouter = GoRouter(
|
|
routes: [
|
|
GoRoute(
|
|
path: RoutePaths.home,
|
|
builder: (context, state) => const HomeScreen(),
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.import_,
|
|
builder: (context, state) => const ImportScreen(),
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.roleSelection,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final Script script) {
|
|
return RoleSelectionScreen(script: script);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.schedule,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final Map<String, Object> extra) {
|
|
return ScheduleScreen(
|
|
script: extra['script']! as Script,
|
|
selectedRole: extra['role']! as Role,
|
|
);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.rehearsal,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final Map<String, Object> extra) {
|
|
return RehearsalScreen(
|
|
script: extra['script']! as Script,
|
|
selectedRole: extra['role']! as Role,
|
|
);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.srsReview,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final List<SrsCard> cards) {
|
|
return SrsReviewScreen(cards: cards);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.annotations,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final Script script) {
|
|
return AnnotationEditorScreen(script: script);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
GoRoute(
|
|
path: RoutePaths.annotationHistory,
|
|
redirect: (context, state) =>
|
|
state.extra == null ? RoutePaths.home : null,
|
|
builder: (context, state) {
|
|
if (state.extra case final Script script) {
|
|
return AnnotationHistoryScreen(script: script);
|
|
}
|
|
return const SizedBox.shrink();
|
|
},
|
|
),
|
|
],
|
|
errorBuilder: (context, state) => Scaffold(
|
|
appBar: AppBar(title: const Text('Not Found')),
|
|
body: Center(
|
|
child: Text('Page not found: ${state.uri}'),
|
|
),
|
|
),
|
|
);
|