alroyso 1 年間 前
コミット
7603faeedc

+ 1 - 0
ios/Flutter/Debug.xcconfig

@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
 #include "Generated.xcconfig"

+ 1 - 0
ios/Flutter/Release.xcconfig

@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
 #include "Generated.xcconfig"

+ 12 - 0
lib/app/modules/home/bindings/home_binding.dart

@@ -0,0 +1,12 @@
+import 'package:get/get.dart';
+
+import '../controllers/home_controller.dart';
+
+class HomeBinding extends Bindings {
+  @override
+  void dependencies() {
+    Get.lazyPut<HomeController>(
+      () => HomeController(),
+    );
+  }
+}

+ 23 - 0
lib/app/modules/home/controllers/home_controller.dart

@@ -0,0 +1,23 @@
+import 'package:get/get.dart';
+
+class HomeController extends GetxController {
+  //TODO: Implement HomeController
+
+  final count = 0.obs;
+  @override
+  void onInit() {
+    super.onInit();
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+  }
+
+  void increment() => count.value++;
+}

+ 24 - 0
lib/app/modules/home/views/home_view.dart

@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+
+import 'package:get/get.dart';
+
+import '../controllers/home_controller.dart';
+
+class HomeView extends GetView<HomeController> {
+  const HomeView({Key? key}) : super(key: key);
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('HomeView'),
+        centerTitle: true,
+      ),
+      body: const Center(
+        child: Text(
+          'HomeView is working',
+          style: TextStyle(fontSize: 20),
+        ),
+      ),
+    );
+  }
+}

+ 20 - 0
lib/app/routes/app_pages.dart

@@ -0,0 +1,20 @@
+import 'package:get/get.dart';
+
+import '../modules/home/bindings/home_binding.dart';
+import '../modules/home/views/home_view.dart';
+
+part 'app_routes.dart';
+
+class AppPages {
+  AppPages._();
+
+  static const INITIAL = Routes.HOME;
+
+  static final routes = [
+    GetPage(
+      name: _Paths.HOME,
+      page: () => const HomeView(),
+      binding: HomeBinding(),
+    ),
+  ];
+}

+ 12 - 0
lib/app/routes/app_routes.dart

@@ -0,0 +1,12 @@
+part of 'app_pages.dart';
+// DO NOT EDIT. This is code generated via package:get_cli/get_cli.dart
+
+abstract class Routes {
+  Routes._();
+  static const HOME = _Paths.HOME;
+}
+
+abstract class _Paths {
+  _Paths._();
+  static const HOME = '/home';
+}

+ 39 - 0
lib/app/util/log.dart

@@ -0,0 +1,39 @@
+import 'dart:io';
+
+import 'package:intl/intl.dart';
+import 'package:logger/logger.dart';
+import 'package:speed_safe/app/util/system.dart';
+import 'package:path/path.dart' as p;
+class MyFilter extends LogFilter {
+  @override
+  bool shouldLog(LogEvent event) {
+    return true;
+  }
+}
+
+late final Logger logger;
+
+class SLog {
+
+  static final DateFormat formatter = DateFormat('yyyy-MM-dd-HH-mm-ss');
+
+  static String getLogPath(String coreName) {
+    final now = formatter.format(DateTime.now());
+    return p.join(logPath, '$coreName-$now.log');
+  }
+
+  static void initLogger(bool saveLog, int methodCount, int errorMethodCount) {
+    logger = Logger(
+      level: Level.verbose,
+      filter: MyFilter(),
+      printer: PrettyPrinter(
+        colors: false,
+        printTime: true,
+        errorMethodCount: errorMethodCount,
+        methodCount: methodCount,
+        noBoxingByDefault: true,
+      ),
+      output: saveLog ? FileOutput(file: File(getLogPath('speedSafe'))) : null,
+    );
+  }
+}

+ 247 - 0
lib/app/util/system.dart

@@ -0,0 +1,247 @@
+import 'dart:io';
+import 'package:speed_safe/app/util/log.dart';
+import 'package:path/path.dart' as p;
+enum OS { windows, linux, macos }
+enum Architecture { x86_64, arm64 }
+
+
+const speedVersion = '0.7.6';
+const speedBuildNumber = 7;
+const speedFullVersion = '$speedVersion+$speedBuildNumber';
+const speedLastCommitHash = 'SELF_BUILD';
+
+
+class SystemUtil{
+  static late final OS os;
+  static late final Architecture architecture;
+  static late final bool isRoot;
+
+  static void init() {
+    os = determineOS();
+    architecture = determineArchitecture();
+    isRoot = determineIsRoot();
+  }
+
+  static OS determineOS() {
+    if(Platform.isWindows) {
+      return OS.windows;
+    } else if (Platform.isLinux) {
+      return OS.linux;
+    } else if (Platform.isMacOS){
+      return OS.macos;
+    } else {
+      logger.e('Unsupported OS');
+      throw Exception('Unsupported OS');
+    }
+  }
+
+  static Architecture determineArchitecture() {
+    if (os == OS.windows) {
+      final arch = Platform.environment['PROCESSOR_ARCHITECTURE'];
+      // https://learn.microsoft.com/en-us/windows/win32/winprog64/wow64-implementation-details
+      if (arch == 'AMD64') {
+        return Architecture.x86_64;
+      } else if (arch == 'ARM64') {
+        return Architecture.arm64;
+      } else {
+        logger.e('Unsupported Architecture');
+        throw Exception('Unsupported Architecture');
+      }
+    } else {
+      final result = Process.runSync('uname', ['-m']);
+      if (result.exitCode == 0) {
+        final arch = result.stdout.toString().trim();
+        if (arch == 'x86_64') {
+          return Architecture.x86_64;
+        } else if (arch == 'aarch64' || arch == 'arm64') {
+          return Architecture.arm64;
+        } else {
+          logger.e('Unsupported Architecture');
+          throw Exception('Unsupported Architecture');
+        }
+      } else {
+        logger.e('Unsupported Architecture');
+        throw Exception('Unsupported Architecture');
+      }
+    }
+  }
+
+
+  static bool determineIsRoot() {
+    if (os == OS.windows) {
+      final result = Process.runSync('net', ['session']);
+      if (result.exitCode == 0) {
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      final result = Process.runSync('id', ['-u']);
+      if (result.exitCode == 0) {
+        return result.stdout.toString().trim() == '0';
+      } else {
+        return false;
+      }
+    }
+  }
+
+
+
+  static void enableWindowsProxy(String listen, int httpPort) async {
+    await runCommand('reg', [
+      'add',
+      'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
+      '/v',
+      'ProxyEnable',
+      '/t',
+      'REG_DWORD',
+      '/d',
+      '1',
+      '/f'
+    ]);
+    await runCommand('reg', [
+      'add',
+      'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
+      '/v',
+      'ProxyServer',
+      '/d',
+      '$listen:$httpPort',
+      '/f'
+    ]);
+    await runCommand('reg', [
+      'add',
+      'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
+      '/v',
+      'ProxyOverride',
+      '/d',
+      '127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*',
+      '/f'
+    ]);
+  }
+
+  static void disableWindowsProxy() async {
+    await runCommand('reg', [
+      'add',
+      'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings',
+      '/v',
+      'ProxyEnable',
+      '/t',
+      'REG_DWORD',
+      '/d',
+      '0',
+      '/f'
+    ]);
+  }
+
+  static void enableMacOSProxy(String listen, int httpPort) async {
+    await runCommand(
+        'networksetup', ['-setwebproxy', 'wi-fi', listen, httpPort.toString()]);
+    await runCommand('networksetup',
+        ['-setsecurewebproxy', 'wi-fi', listen, httpPort.toString()]);
+    await runCommand('networksetup', ['-setwebproxystate', 'wi-fi', 'on']);
+    await runCommand(
+        'networksetup', ['-setsecurewebproxystate', 'wi-fi', 'on']);
+  }
+
+  static void disableMacOSProxy() async {
+    await runCommand('networksetup', ['-setwebproxystate', 'wi-fi', 'off']);
+    await runCommand(
+        'networksetup', ['-setsecurewebproxystate', 'wi-fi', 'off']);
+  }
+
+
+  static Future<void> runCommand(
+      String executable, List<String> arguments) async {
+    final result = await Process.run(executable, arguments, runInShell: true);
+    if (result.exitCode != 0) {
+      logger.e('Failed to run command: $executable $arguments');
+      throw Exception('Failed to run command: $executable $arguments');
+    }
+  }
+
+  static String getCoreFileName(String coreName) {
+    final ext = os == OS.windows ? '.exe' : '';
+    switch (coreName) {
+      case 'sing-box':
+        return 'sing-box$ext';
+      case 'xray-core':
+        return 'xray$ext';
+      case 'shadowsocks-rust':
+        return 'sslocal$ext';
+      case 'hysteria':
+        final plat = os == OS.macos ? 'darwin' : os.name;
+        final arch = architecture == Architecture.arm64 ? 'arm64' : 'amd64';
+        return 'hysteria-$plat-$arch$ext';
+      case 'sphia':
+        return 'sphia$ext';
+      case 'upgradeAgent':
+        return 'upgradeAgent$ext';
+      default:
+        throw Exception('Unsupported core: $coreName');
+    }
+  }
+
+  static void setFilePermission(String fileName) {
+    if (os != OS.windows) {
+      Process.runSync('chmod', ['+x', fileName]);
+    }
+  }
+
+  static void createDirectory(String dirName) {
+    final dir = Directory(dirName);
+    try {
+      if (!dir.existsSync()) {
+        logger.i('Creating directory: $dirName');
+        dir.createSync();
+      }
+    } catch (e) {
+      logger.e('Error creating directory: $e');
+    }
+  }
+  static bool fileExists(String fileName) {
+    return File(p.join(binPath, fileName)).existsSync();
+  }
+
+  static void deleteFileIfExists(String filePath, String logMessage) {
+    final file = File(filePath);
+    if (file.existsSync()) {
+      logger.i(logMessage);
+      file.deleteSync();
+    }
+  }
+
+  static bool coreExists(String coreName) {
+    if (coreName == 'sing-box-rules') {
+      return fileExists(p.join(binPath, 'geoip.db')) &&
+          fileExists(p.join(binPath, 'geosite.db'));
+    } else if (coreName == 'v2ray-rules-dat') {
+      return fileExists(p.join(binPath, 'geoip.dat')) &&
+          fileExists(p.join(binPath, 'geosite.dat'));
+    } else {
+      return fileExists(p.join(binPath, getCoreFileName(coreName)));
+    }
+  }
+  // static List<String> getCoreFileNames() {
+  //   List<String> fileNames = [];
+  //   coreRepositories.entries
+  //       .toList()
+  //       .sublist(0, coreRepositories.length - 3)
+  //       .forEach((entry) {
+  //     fileNames.add(getCoreFileName(entry.key));
+  //   });
+  //   return fileNames;
+  // }
+  static void initPaths() {
+    binPath = p.join(appPath, 'bin');
+    configPath = p.join(appPath, 'config');
+    logPath = p.join(appPath, 'log');
+    tempPath = p.join(appPath, 'temp');
+  }
+}
+
+late final String execPath;
+late final String appPath;
+late String binPath;
+late String configPath;
+late String logPath;
+late String tempPath;

+ 110 - 112
lib/main.dart

@@ -1,125 +1,123 @@
+import 'dart:io';
+
 import 'package:flutter/material.dart';
 
-void main() {
-  runApp(const MyApp());
-}
+import 'package:get/get.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:speed_safe/app/util/log.dart';
+import 'package:speed_safe/app/util/system.dart';
+import 'package:window_manager/window_manager.dart';
+
+import 'app/routes/app_pages.dart';
 
-class MyApp extends StatelessWidget {
-  const MyApp({super.key});
-
-  // This widget is the root of your application.
-  @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      title: 'Flutter Demo',
-      theme: ThemeData(
-        // This is the theme of your application.
-        //
-        // TRY THIS: Try running your application with "flutter run". You'll see
-        // the application has a blue toolbar. Then, without quitting the app,
-        // try changing the seedColor in the colorScheme below to Colors.green
-        // and then invoke "hot reload" (save your changes or press the "hot
-        // reload" button in a Flutter-supported IDE, or press "r" if you used
-        // the command line to start the app).
-        //
-        // Notice that the counter didn't reset back to zero; the application
-        // state is not lost during the reload. To reset the state, use hot
-        // restart instead.
-        //
-        // This works for code too, not just values: Most code changes can be
-        // tested with just a hot reload.
-        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
-        useMaterial3: true,
-      ),
-      home: const MyHomePage(title: 'Flutter Demo Home Page'),
-    );
+
+Future<void> getAppPath() async{
+  if (Platform.isLinux && Platform.environment.containsKey('APPIMAGE')) {
+    execPath = Platform.environment['APPIMAGE']!;
+  } else {
+    execPath = Platform.resolvedExecutable;
+  }
+  if (const bool.fromEnvironment('dart.vm.product')) { //如果是发布
+    if (Platform.isLinux) {
+      final linuxAppPath = (await getApplicationSupportDirectory()).path;
+      final int firstIndex = linuxAppPath.indexOf('/root/');
+      if (firstIndex != -1) {
+        appPath = linuxAppPath.replaceFirst('/root/',
+            '/home/${Platform.environment['SUDO_USER']}/', firstIndex);
+      } else {
+        appPath = linuxAppPath;
+      }
+    } else if (Platform.isMacOS) {
+      final macAppPath = (await getApplicationSupportDirectory()).path;
+      final int firstIndex = macAppPath.indexOf('/var/root/');
+      if (firstIndex != -1) {
+        appPath = macAppPath.replaceFirst('/var/root/',
+            '/Users/${Platform.environment['SUDO_USER']}/', firstIndex);
+      } else {
+        appPath = macAppPath;
+      }
+    } else {
+      appPath =
+          execPath.substring(0, execPath.lastIndexOf(Platform.pathSeparator));
+    }
+  } else {
+    if (Platform.isMacOS) { //如果是调试
+      // For debug
+      appPath = execPath.substring(0, execPath.lastIndexOf('/speed_safe.app'));
+    } else {
+      appPath =
+          execPath.substring(0, execPath.lastIndexOf(Platform.pathSeparator));
+    }
   }
 }
 
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key, required this.title});
+Future<void> initConfig() async {
 
-  // This widget is the home page of your application. It is stateful, meaning
-  // that it has a State object (defined below) that contains fields that affect
-  // how it looks.
+  // Get app path
+  await getAppPath();
 
-  // This class is the configuration for the state. It holds the values (in this
-  // case the title) provided by the parent (in this case the App widget) and
-  // used by the build method of the State. Fields in a Widget subclass are
-  // always marked "final".
+  // init path
+  SystemUtil.initPaths();
 
-  final String title;
+  // Init logger
+  if (const bool.fromEnvironment('dart.vm.product')) {
+    SLog.initLogger(true, 2, 2);
+  } else {
+    SLog.initLogger(false, 5, 5);
+  }
 
-  @override
-  State<MyHomePage> createState() => _MyHomePageState();
-}
+  // Check dir exists
+  SystemUtil.createDirectory(binPath);
+  SystemUtil.createDirectory(configPath);
+  SystemUtil.createDirectory(logPath);
+  SystemUtil.createDirectory(tempPath);
 
-class _MyHomePageState extends State<MyHomePage> {
-  int _counter = 0;
-
-  void _incrementCounter() {
-    setState(() {
-      // This call to setState tells the Flutter framework that something has
-      // changed in this State, which causes it to rerun the build method below
-      // so that the display can reflect the updated values. If we changed
-      // _counter without calling setState(), then the build method would not be
-      // called again, and so nothing would appear to happen.
-      _counter++;
-    });
-  }
+  // Init SystemUtil
+  SystemUtil.init();
 
-  @override
-  Widget build(BuildContext context) {
-    // This method is rerun every time setState is called, for instance as done
-    // by the _incrementCounter method above.
-    //
-    // The Flutter framework has been optimized to make rerunning build methods
-    // fast, so that you can just rebuild anything that needs updating rather
-    // than having to individually change instances of widgets.
-    return Scaffold(
-      appBar: AppBar(
-        // TRY THIS: Try changing the color here to a specific color (to
-        // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
-        // change color while the other colors stay the same.
-        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-        // Here we take the value from the MyHomePage object that was created by
-        // the App.build method, and use it to set our appbar title.
-        title: Text(widget.title),
-      ),
-      body: Center(
-        // Center is a layout widget. It takes a single child and positions it
-        // in the middle of the parent.
-        child: Column(
-          // Column is also a layout widget. It takes a list of children and
-          // arranges them vertically. By default, it sizes itself to fit its
-          // children horizontally, and tries to be as tall as its parent.
-          //
-          // Column has various properties to control how it sizes itself and
-          // how it positions its children. Here we use mainAxisAlignment to
-          // center the children vertically; the main axis here is the vertical
-          // axis because Columns are vertical (the cross axis would be
-          // horizontal).
-          //
-          // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
-          // action in the IDE, or press "p" in the console), to see the
-          // wireframe for each widget.
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            const Text(
-              'You have pushed the button this many times:',
-            ),
-            Text(
-              '$_counter',
-              style: Theme.of(context).textTheme.headlineMedium,
-            ),
-          ],
-        ),
-      ),
-      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
-        tooltip: 'Increment',
-        child: const Icon(Icons.add),
-      ), // This trailing comma makes auto-formatting nicer for build methods.
-    );
-  }
+  final speedInfo = '''
+  SpeedSafe - a Proxy Handling Intuitive Application
+  Full version: $speedFullVersion
+  Last commit hash: $speedLastCommitHash
+  OS: ${SystemUtil.os.name}
+  Architecture: ${SystemUtil.architecture.name}
+  App Path: $appPath
+  Exec Path: $execPath
+  Bin path: $binPath
+  Config path: $configPath
+  Log path: $logPath
+  Temp path: $tempPath''';
+
+  logger.i(speedInfo);
+
+
+
+  WidgetsFlutterBinding.ensureInitialized();
+  // 必须加上这一行。
+  await windowManager.ensureInitialized();
+
+  WindowOptions windowOptions = const WindowOptions(
+    size: Size(800, 600),
+    center: true,
+    backgroundColor: Colors.transparent,
+    skipTaskbar: false,
+    //titleBarStyle: TitleBarStyle.hidden,
+  );
+
+  windowManager.waitUntilReadyToShow(windowOptions, () async {
+    await windowManager.show();
+    await windowManager.focus();
+  });
+  return;
+}
+
+void main() async {
+  await initConfig();
+  runApp(
+    GetMaterialApp(
+      title: "Application",
+      initialRoute: AppPages.INITIAL,
+      getPages: AppPages.routes,
+    ),
+  );
 }

+ 8 - 0
linux/flutter/generated_plugin_registrant.cc

@@ -6,6 +6,14 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <screen_retriever/screen_retriever_plugin.h>
+#include <window_manager/window_manager_plugin.h>
 
 void fl_register_plugins(FlPluginRegistry* registry) {
+  g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
+  screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);
+  g_autoptr(FlPluginRegistrar) window_manager_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin");
+  window_manager_plugin_register_with_registrar(window_manager_registrar);
 }

+ 2 - 0
linux/flutter/generated_plugins.cmake

@@ -3,6 +3,8 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  screen_retriever
+  window_manager
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST

+ 1 - 0
macos/Flutter/Flutter-Debug.xcconfig

@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
 #include "ephemeral/Flutter-Generated.xcconfig"

+ 1 - 0
macos/Flutter/Flutter-Release.xcconfig

@@ -1 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
 #include "ephemeral/Flutter-Generated.xcconfig"

+ 6 - 0
macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,6 +5,12 @@
 import FlutterMacOS
 import Foundation
 
+import path_provider_foundation
+import screen_retriever
+import window_manager
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+  ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
+  WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
 }

+ 97 - 1
macos/Runner.xcodeproj/project.pbxproj

@@ -21,12 +21,14 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+		0B061145D16EA58C8338E7A1 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8D2C1CC84FF3117C1F93103 /* Pods_RunnerTests.framework */; };
 		331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
 		335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
 		33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
 		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
 		33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
 		33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
+		D3DEE6AE8D1C56A495839F9E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D1BAF7B64DA98B7E8CCE774 /* Pods_Runner.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -64,7 +66,7 @@
 		331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
 		333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
 		335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
-		33CC10ED2044A3C60003C045 /* speed_safe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "speed_safe.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		33CC10ED2044A3C60003C045 /* speed_safe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = speed_safe.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
 		33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -76,8 +78,16 @@
 		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
 		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
 		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
+		3D1BAF7B64DA98B7E8CCE774 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		4C21BB73BB0AF5CACDDBE9A4 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
+		4C22D4C539E6518CCEF9B08A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
+		56B44F19B785CEE7ECA99289 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
+		5FDA3DD95DAAFBE3E0AFE084 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
+		94BE036712CBF69468843D6D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
+		C7A8C11A9B4F9812CC752B5E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
+		D8D2C1CC84FF3117C1F93103 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -85,6 +95,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				0B061145D16EA58C8338E7A1 /* Pods_RunnerTests.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -92,6 +103,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				D3DEE6AE8D1C56A495839F9E /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -125,6 +137,7 @@
 				331C80D6294CF71000263BE5 /* RunnerTests */,
 				33CC10EE2044A3C60003C045 /* Products */,
 				D73912EC22F37F3D000D13A0 /* Frameworks */,
+				C9005E7B8B66717318399A0B /* Pods */,
 			);
 			sourceTree = "<group>";
 		};
@@ -172,9 +185,25 @@
 			path = Runner;
 			sourceTree = "<group>";
 		};
+		C9005E7B8B66717318399A0B /* Pods */ = {
+			isa = PBXGroup;
+			children = (
+				4C22D4C539E6518CCEF9B08A /* Pods-Runner.debug.xcconfig */,
+				5FDA3DD95DAAFBE3E0AFE084 /* Pods-Runner.release.xcconfig */,
+				94BE036712CBF69468843D6D /* Pods-Runner.profile.xcconfig */,
+				4C21BB73BB0AF5CACDDBE9A4 /* Pods-RunnerTests.debug.xcconfig */,
+				56B44F19B785CEE7ECA99289 /* Pods-RunnerTests.release.xcconfig */,
+				C7A8C11A9B4F9812CC752B5E /* Pods-RunnerTests.profile.xcconfig */,
+			);
+			name = Pods;
+			path = Pods;
+			sourceTree = "<group>";
+		};
 		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				3D1BAF7B64DA98B7E8CCE774 /* Pods_Runner.framework */,
+				D8D2C1CC84FF3117C1F93103 /* Pods_RunnerTests.framework */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -186,6 +215,7 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
 			buildPhases = (
+				8FCA7F8B3E09297A925CD9B8 /* [CP] Check Pods Manifest.lock */,
 				331C80D1294CF70F00263BE5 /* Sources */,
 				331C80D2294CF70F00263BE5 /* Frameworks */,
 				331C80D3294CF70F00263BE5 /* Resources */,
@@ -204,11 +234,13 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
 			buildPhases = (
+				B8CC4E2AFAAC22A662021FBA /* [CP] Check Pods Manifest.lock */,
 				33CC10E92044A3C60003C045 /* Sources */,
 				33CC10EA2044A3C60003C045 /* Frameworks */,
 				33CC10EB2044A3C60003C045 /* Resources */,
 				33CC110E2044A8840003C045 /* Bundle Framework */,
 				3399D490228B24CF009A79C7 /* ShellScript */,
+				C34900DFA92EC3D4D434BA80 /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -328,6 +360,67 @@
 			shellPath = /bin/sh;
 			shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
 		};
+		8FCA7F8B3E09297A925CD9B8 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		B8CC4E2AFAAC22A662021FBA /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputFileListPaths = (
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			showEnvVarsInLog = 0;
+		};
+		C34900DFA92EC3D4D434BA80 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -379,6 +472,7 @@
 /* Begin XCBuildConfiguration section */
 		331C80DB294CF71000263BE5 /* Debug */ = {
 			isa = XCBuildConfiguration;
+			baseConfigurationReference = 4C21BB73BB0AF5CACDDBE9A4 /* Pods-RunnerTests.debug.xcconfig */;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CURRENT_PROJECT_VERSION = 1;
@@ -393,6 +487,7 @@
 		};
 		331C80DC294CF71000263BE5 /* Release */ = {
 			isa = XCBuildConfiguration;
+			baseConfigurationReference = 56B44F19B785CEE7ECA99289 /* Pods-RunnerTests.release.xcconfig */;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CURRENT_PROJECT_VERSION = 1;
@@ -407,6 +502,7 @@
 		};
 		331C80DD294CF71000263BE5 /* Profile */ = {
 			isa = XCBuildConfiguration;
+			baseConfigurationReference = C7A8C11A9B4F9812CC752B5E /* Pods-RunnerTests.profile.xcconfig */;
 			buildSettings = {
 				BUNDLE_LOADER = "$(TEST_HOST)";
 				CURRENT_PROJECT_VERSION = 1;

+ 3 - 0
macos/Runner.xcworkspace/contents.xcworkspacedata

@@ -4,4 +4,7 @@
    <FileRef
       location = "group:Runner.xcodeproj">
    </FileRef>
+   <FileRef
+      location = "group:Pods/Pods.xcodeproj">
+   </FileRef>
 </Workspace>

+ 2 - 4
macos/Runner/DebugProfile.entitlements

@@ -2,11 +2,9 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>com.apple.security.app-sandbox</key>
-	<true/>
-	<key>com.apple.security.cs.allow-jit</key>
-	<true/>
 	<key>com.apple.security.network.server</key>
 	<true/>
+	<key>com.apple.security.network.client</key>
+    <true/>
 </dict>
 </plist>

+ 4 - 2
macos/Runner/Release.entitlements

@@ -2,7 +2,9 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-	<key>com.apple.security.app-sandbox</key>
-	<true/>
+    <key>com.apple.security.network.server</key>
+    <true/>
+	<key>com.apple.security.network.client</key>
+    <true/>
 </dict>
 </plist>

+ 138 - 1
pubspec.lock

@@ -57,6 +57,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.1"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -75,6 +83,30 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  get:
+    dependency: "direct main"
+    description:
+      name: get
+      sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.6.6"
+  intl:
+    dependency: "direct main"
+    description:
+      name: intl
+      sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.18.1"
+  json_annotation:
+    dependency: "direct main"
+    description:
+      name: json_annotation
+      sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.8.1"
   lints:
     dependency: transitive
     description:
@@ -83,6 +115,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.1"
+  logger:
+    dependency: "direct main"
+    description:
+      name: logger
+      sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.2+1"
   matcher:
     dependency: transitive
     description:
@@ -108,13 +148,85 @@ packages:
     source: hosted
     version: "1.9.1"
   path:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: path
       sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
       url: "https://pub.dev"
     source: hosted
     version: "1.8.3"
+  path_provider:
+    dependency: "direct main"
+    description:
+      name: path_provider
+      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.1"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.3"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.6"
+  screen_retriever:
+    dependency: transitive
+    description:
+      name: screen_retriever
+      sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.1.9"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -184,5 +296,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.1.4-beta"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.0.9"
+  window_manager:
+    dependency: "direct main"
+    description:
+      name: window_manager
+      sha256: dcc865277f26a7dad263a47d0e405d77e21f12cb71f30333a52710a408690bd7
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.7"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
 sdks:
   dart: ">=3.1.1 <4.0.0"
+  flutter: ">=3.13.0"

+ 16 - 80
pubspec.yaml

@@ -1,90 +1,26 @@
 name: speed_safe
-description: A new Flutter project.
-# The following line prevents the package from being accidentally published to
-# pub.dev using `flutter pub publish`. This is preferred for private packages.
-publish_to: 'none' # Remove this line if you wish to publish to pub.dev
-
-# The following defines the version and build number for your application.
-# A version number is three numbers separated by dots, like 1.2.43
-# followed by an optional build number separated by a +.
-# Both the version and the builder number may be overridden in flutter
-# build by specifying --build-name and --build-number, respectively.
-# In Android, build-name is used as versionName while build-number used as versionCode.
-# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
-# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
-# Read more about iOS versioning at
-# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-# In Windows, build-name is used as the major, minor, and patch parts
-# of the product and file versions while build-number is used as the build suffix.
 version: 1.0.0+1
-
-environment:
+publish_to: none
+description: A new Flutter project.
+environment: 
   sdk: '>=3.1.1 <4.0.0'
 
-# Dependencies specify other packages that your package needs in order to work.
-# To automatically upgrade your package dependencies to the latest versions
-# consider running `flutter pub upgrade --major-versions`. Alternatively,
-# dependencies can be manually updated by changing the version numbers below to
-# the latest version available on pub.dev. To see which dependencies have newer
-# versions available, run `flutter pub outdated`.
-dependencies:
-  flutter:
-    sdk: flutter
-
-
-  # The following adds the Cupertino Icons font to your application.
-  # Use with the CupertinoIcons class for iOS style icons.
+dependencies: 
   cupertino_icons: ^1.0.2
-
-dev_dependencies:
-  flutter_test:
+  get: 4.6.6
+  flutter: 
     sdk: flutter
-
-  # The "flutter_lints" package below contains a set of recommended lints to
-  # encourage good coding practices. The lint set provided by the package is
-  # activated in the `analysis_options.yaml` file located at the root of your
-  # package. See that file for information about deactivating specific lint
-  # rules and activating additional ones.
+  window_manager: ^0.3.7
+  logger: ^2.0.2+1
+  intl: ^0.18.1
+  json_annotation: ^4.8.1
+  path_provider: ^2.1.1
+  path: ^1.8.3
+dev_dependencies: 
   flutter_lints: ^2.0.0
+  flutter_test: 
+    sdk: flutter
 
-# For information on the generic Dart part of this file, see the
-# following page: https://dart.dev/tools/pub/pubspec
-
-# The following section is specific to Flutter packages.
-flutter:
-
-  # The following line ensures that the Material Icons font is
-  # included with your application, so that you can use the icons in
-  # the material Icons class.
+flutter: 
   uses-material-design: true
 
-  # To add assets to your application, add an assets section, like this:
-  # assets:
-  #   - images/a_dot_burr.jpeg
-  #   - images/a_dot_ham.jpeg
-
-  # An image asset can refer to one or more resolution-specific "variants", see
-  # https://flutter.dev/assets-and-images/#resolution-aware
-
-  # For details regarding adding assets from package dependencies, see
-  # https://flutter.dev/assets-and-images/#from-packages
-
-  # To add custom fonts to your application, add a fonts section here,
-  # in this "flutter" section. Each entry in this list should have a
-  # "family" key with the font family name, and a "fonts" key with a
-  # list giving the asset and other descriptors for the font. For
-  # example:
-  # fonts:
-  #   - family: Schyler
-  #     fonts:
-  #       - asset: fonts/Schyler-Regular.ttf
-  #       - asset: fonts/Schyler-Italic.ttf
-  #         style: italic
-  #   - family: Trajan Pro
-  #     fonts:
-  #       - asset: fonts/TrajanPro.ttf
-  #       - asset: fonts/TrajanPro_Bold.ttf
-  #         weight: 700
-  #
-  # For details regarding fonts from package dependencies,
-  # see https://flutter.dev/custom-fonts/#from-packages

+ 1 - 1
test/widget_test.dart

@@ -13,7 +13,7 @@ import 'package:speed_safe/main.dart';
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {
     // Build our app and trigger a frame.
-    await tester.pumpWidget(const MyApp());
+    //await tester.pumpWidget(const MyApp());
 
     // Verify that our counter starts at 0.
     expect(find.text('0'), findsOneWidget);

+ 6 - 0
windows/flutter/generated_plugin_registrant.cc

@@ -6,6 +6,12 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <screen_retriever/screen_retriever_plugin.h>
+#include <window_manager/window_manager_plugin.h>
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
+  ScreenRetrieverPluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
+  WindowManagerPluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("WindowManagerPlugin"));
 }

+ 2 - 0
windows/flutter/generated_plugins.cmake

@@ -3,6 +3,8 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  screen_retriever
+  window_manager
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST