feat: unified shell, diagnostics pack, native Office, sticky board
All checks were successful
CI / Windows build (push) Successful in 14m22s

Make Surface remote debugging and classroom workflows viable: always-on
structured logs with one-click zip export, a single AppShell chrome,
OOXML PPTX/DOCX annotation without LibreOffice, and a first-class sticky
board. Also drop spike/legacy ink widgets and tighten pen feel
(predictor, PenInfoHistory, page-tile layer).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-05 17:55:27 +08:00
parent 3cabc7e074
commit d346cc2670
49 changed files with 2883 additions and 2515 deletions

View File

@@ -2,15 +2,15 @@ import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:pdfrx/pdfrx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'editor/persistence/sidecar_flush_observer.dart';
import 'editor/pdf/pen_capture_region.dart';
import 'theme/app_theme.dart';
import 'diagnostics/badnote_log.dart';
import 'l10n/app_localizations.dart';
import 'providers/settings_provider.dart';
import 'screens/home_screen.dart';
import 'screens/app_shell.dart';
import 'screens/vault_setup_screen.dart';
import 'services/database_service.dart';
import 'services/vault_service.dart';
@@ -18,11 +18,7 @@ import 'services/webdav_sync_service.dart';
import 'storage/sqlite_to_sidecar_migrator.dart';
Future<void> main() async {
// Kind-aware binding (extends WidgetsFlutterBinding) must be the active
// binding before runApp so the M1 spike's PenCaptureRegion can gate
// hit-testing by pointer kind. Safe for the rest of the app: with no pen
// region mounted it behaves exactly like the default binding.
PenCaptureBinding.ensureInitialized();
WidgetsFlutterBinding.ensureInitialized();
// pdfrx native engine init (required before any PdfViewer is built).
pdfrxFlutterInitialize();
@@ -32,6 +28,10 @@ Future<void> main() async {
// Initialize SharedPreferences
await SharedPreferences.getInstance();
// Always-on structured diagnostics (Surface remote debugging).
await BadNoteLog.instance.start();
BadNoteLog.instance.info(LogSubsystem.shell, 'app_start');
runApp(const ProviderScope(child: BadNoteApp()));
}
@@ -81,8 +81,8 @@ class _BadNoteAppState extends ConsumerState<BadNoteApp> {
return MaterialApp(
title: 'BadNote',
themeMode: settings.themeMode,
theme: _theme(lightScheme),
darkTheme: _theme(darkScheme),
theme: AppTheme.fromScheme(lightScheme),
darkTheme: AppTheme.fromScheme(darkScheme),
// i18n: follows the OS language (en / zh) via the system locale.
localizationsDelegates: const [
AppLocalizations.delegate,
@@ -96,14 +96,6 @@ class _BadNoteAppState extends ConsumerState<BadNoteApp> {
},
);
}
ThemeData _theme(ColorScheme scheme) => ThemeData(
colorScheme: scheme,
useMaterial3: true,
textTheme: GoogleFonts.interTextTheme(
ThemeData(brightness: scheme.brightness).textTheme,
),
);
}
/// Startup gate: shows [HomeScreen] only once a valid vault root folder has been
@@ -213,7 +205,7 @@ class _VaultGateState extends State<VaultGate> {
),
);
}
if (_valid) return const HomeScreen();
if (_valid) return const AppShell();
return VaultSetupScreen(
vaultService: _vault!,
missing: _hadStoredPath,