arblant
Railynx / lib / main.dart
main.dart85 lines · 2.7 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

import 'app/controller.dart';
import 'app/fps.dart';
import 'app/prefs_store.dart';
import 'app/probe_engine.dart';
import 'app/tokens.dart';
import 'ui/home_page.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // On Android the executable directory is read-only, so settings live in
  // the app documents folder instead; on desktop they stay beside the
  // executable, as the Python app kept them.
  final PrefsStore prefs;
  if (Platform.isAndroid) {
    final dir = await getApplicationDocumentsDirectory();
    prefs = PrefsStore(File('${dir.path}/railway_scanner_prefs.json'));
  } else {
    prefs = PrefsStore.beside(Platform.resolvedExecutable);
  }
  final controller = AppController(engine: RealProbeEngine(), prefs: prefs);
  await applyFpsLimit(controller.fpsLimit);
  runApp(ScannerApp(controller: controller));
}

class ScannerApp extends StatelessWidget {
  const ScannerApp({super.key, required this.controller});

  final AppController controller;

  @override
  Widget build(BuildContext context) {
    final scheme = ColorScheme.fromSeed(
      seedColor: Tokens.teal,
      brightness: Brightness.dark,
    );
    return MaterialApp(
      title: 'Railynx',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.dark,
        colorScheme: scheme,
        scaffoldBackgroundColor: Tokens.bg,
        fontFamily: Tokens.uiFont,
        textSelectionTheme: const TextSelectionThemeData(cursorColor: Tokens.teal),
        inputDecorationTheme: InputDecorationTheme(
          filled: true,
          fillColor: Tokens.surface,
          isDense: true,
          hintStyle: const TextStyle(color: Tokens.ink3, fontSize: 13),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(12),
            borderSide: BorderSide(color: Tokens.edge.withValues(alpha: 0.16)),
          ),
          enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(12),
            borderSide: BorderSide(color: Tokens.edge.withValues(alpha: 0.16)),
          ),
          focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(12),
            borderSide: const BorderSide(color: Tokens.teal),
          ),
        ),
      ),
      home: _Shell(controller: controller),
    );
  }
}

/// Wraps the page so SnackBars have a ScaffoldMessenger above HomePage.
class _Shell extends StatelessWidget {
  const _Shell({required this.controller});

  final AppController controller;

  @override
  Widget build(BuildContext context) {
    return ScaffoldMessenger(child: HomePage(controller: controller));
  }
}