周睿 vor 2 Jahren
Ursprung
Commit
a31ffffd69
52 geänderte Dateien mit 2480 neuen und 116 gelöschten Zeilen
  1. 3 0
      .gitmodules
  2. 2 2
      app_business/android/app/build.gradle
  3. 2 1
      app_business/android/build.gradle
  4. 2 1
      app_business/android/gradle/wrapper/gradle-wrapper.properties
  5. 3 0
      app_business/l10n.yaml
  6. 3 0
      app_business/lib/l10n/app_en.arb
  7. 3 0
      app_business/lib/l10n/app_zh.arb
  8. 17 111
      app_business/lib/main.dart
  9. 20 0
      app_business/lib/pages.dart
  10. 13 0
      app_business/lib/view/all_init.dart
  11. 21 0
      app_business/lib/view/login.dart
  12. 4 0
      app_business/linux/flutter/generated_plugin_registrant.cc
  13. 1 0
      app_business/linux/flutter/generated_plugins.cmake
  14. 6 0
      app_business/macos/Flutter/GeneratedPluginRegistrant.swift
  15. 465 0
      app_business/pubspec.lock
  16. 19 1
      app_business/pubspec.yaml
  17. 6 0
      app_business/windows/flutter/generated_plugin_registrant.cc
  18. 2 0
      app_business/windows/flutter/generated_plugins.cmake
  19. 1 0
      libs/common_pub
  20. 50 0
      libs/track_common/.gitignore
  21. 10 0
      libs/track_common/.metadata
  22. 11 0
      libs/track_common/README.md
  23. 4 0
      libs/track_common/analysis_options.yaml
  24. BIN
      libs/track_common/assets/images/am_app_start_arrow.riv
  25. BIN
      libs/track_common/assets/images/bk_common_page.png
  26. BIN
      libs/track_common/assets/images/bk_login.png
  27. BIN
      libs/track_common/assets/images/bk_login_right.png
  28. BIN
      libs/track_common/assets/images/ic_cp.png
  29. BIN
      libs/track_common/assets/images/ic_location.png
  30. BIN
      libs/track_common/assets/images/ic_login_logo.png
  31. BIN
      libs/track_common/assets/images/ic_map_scale.png
  32. BIN
      libs/track_common/assets/images/ic_no_data.png
  33. BIN
      libs/track_common/assets/images/im_compass_no_map.png
  34. 17 0
      libs/track_common/lib/generated/assets.dart
  35. 1 0
      libs/track_common/lib/service.dart
  36. 1 0
      libs/track_common/lib/service/all_init.dart
  37. 71 0
      libs/track_common/lib/styles/color_schemes.g.dart
  38. 11 0
      libs/track_common/lib/styles/theme.dart
  39. 3 0
      libs/track_common/lib/track_common.dart
  40. 90 0
      libs/track_common/lib/utils.dart
  41. 3 0
      libs/track_common/lib/view.dart
  42. 71 0
      libs/track_common/lib/view/init_view.dart
  43. 132 0
      libs/track_common/lib/view/login/common.dart
  44. 133 0
      libs/track_common/lib/view/login/login_controller.dart
  45. 415 0
      libs/track_common/lib/view/login/login_view.dart
  46. 98 0
      libs/track_common/lib/view/login/logo_widget.dart
  47. 6 0
      libs/track_common/lib/widget.dart
  48. 6 0
      libs/track_common/lib/widget/prelude.dart
  49. 16 0
      libs/track_common/lib/widget/title_point.dart
  50. 633 0
      libs/track_common/pubspec.lock
  51. 93 0
      libs/track_common/pubspec.yaml
  52. 12 0
      libs/track_common/test/widget_test.dart

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "libs/common_pub"]
+	path = libs/common_pub
+	url = git@git.beswell.com:Orienteering/common_pub.git

+ 2 - 2
app_business/android/app/build.gradle

@@ -25,8 +25,8 @@ if (flutterVersionName == null) {
 android {
     namespace "com.colormaprun.orienteering.app_business.app_business"
     compileSdkVersion flutter.compileSdkVersion
-    ndkVersion flutter.ndkVersion
-
+//    ndkVersion flutter.ndkVersion
+    ndkVersion "25.1.8937393"
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_8
         targetCompatibility JavaVersion.VERSION_1_8

+ 2 - 1
app_business/android/build.gradle

@@ -6,7 +6,7 @@ buildscript {
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:7.3.0'
+        classpath 'com.android.tools.build:gradle:8.1.1'
         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
     }
 }
@@ -15,6 +15,7 @@ allprojects {
     repositories {
         google()
         mavenCentral()
+        maven { url 'https://mirrors.tuna.tsinghua.edu.cn/flutter/download.flutter.io' }
     }
 }
 

+ 2 - 1
app_business/android/gradle/wrapper/gradle-wrapper.properties

@@ -2,4 +2,5 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
+

+ 3 - 0
app_business/l10n.yaml

@@ -0,0 +1,3 @@
+arb-dir: lib/l10n
+template-arb-file: app_en.arb
+output-localization-file: app_localizations.dart

+ 3 - 0
app_business/lib/l10n/app_en.arb

@@ -0,0 +1,3 @@
+{
+  "helloWorld": "Hello World!"
+}

+ 3 - 0
app_business/lib/l10n/app_zh.arb

@@ -0,0 +1,3 @@
+{
+  "helloWorld": "你好,世界!"
+}

+ 17 - 111
app_business/lib/main.dart

@@ -1,125 +1,31 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:get/get.dart';
+import 'package:track_common/track_common.dart';
+import 'package:track_common/view.dart';
+
+import 'pages.dart';
 
 void main() {
+  WidgetsFlutterBinding.ensureInitialized();
   runApp(const MyApp());
 }
 
 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'),
-    );
-  }
-}
-
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key, required this.title});
-
-  // 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.
-
-  // 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".
-
-  final String title;
-
-  @override
-  State<MyHomePage> createState() => _MyHomePageState();
-}
-
-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++;
-    });
-  }
-
   @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.
+    info('size: ${MediaQuery.of(context).size}');
+    return GetMaterialApp(
+      debugShowCheckedModeBanner: true,
+      title: '小飞龙定向场控',
+      theme: appThemeData(),
+      darkTheme: appThemeData(),
+      localizationsDelegates: AppLocalizations.localizationsDelegates,
+      supportedLocales: AppLocalizations.supportedLocales,
+      getPages: getPages,
+      initialRoute: InitView.name,
     );
   }
 }

+ 20 - 0
app_business/lib/pages.dart

@@ -0,0 +1,20 @@
+import 'package:get/get.dart';
+import 'package:track_common/view.dart';
+
+import 'view/all_init.dart';
+import 'view/login.dart';
+
+final getPages = [
+  GetPage(
+      name: InitView.name,
+      page: () => const InitView(),
+      binding: BindingsBuilder(() {
+        Get.put<InitController>(InitControllerImp());
+      })),
+  GetPage(
+      name: LoginView.name,
+      page: () => const LoginView(),
+      binding: BindingsBuilder(() {
+        Get.put<LoginController>(LoginControllerImp());
+      }))
+];

+ 13 - 0
app_business/lib/view/all_init.dart

@@ -0,0 +1,13 @@
+import 'package:track_common/view.dart';
+
+class InitControllerImp extends InitController {
+  @override
+  Future<void> allInit() async {
+    return;
+  }
+
+  @override
+  Future<bool> isNeedLogin() async {
+    return true;
+  }
+}

+ 21 - 0
app_business/lib/view/login.dart

@@ -0,0 +1,21 @@
+import 'package:get/get.dart';
+import 'package:track_common/view.dart';
+
+class LoginControllerImp extends LoginController {
+  @override
+  Future<void> authSendCodeToPhone(String phone) async {
+    // TODO: implement authSendCodeToPhone
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<Duration> getCodeLifeTime(String phone) async {
+    return 0.seconds;
+  }
+
+  @override
+  Future<void> signIn(String phone, String code) async {
+    // TODO: implement signIn
+    throw UnimplementedError();
+  }
+}

+ 4 - 0
app_business/linux/flutter/generated_plugin_registrant.cc

@@ -6,6 +6,10 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <common_pub/common_pub_plugin.h>
 
 void fl_register_plugins(FlPluginRegistry* registry) {
+  g_autoptr(FlPluginRegistrar) common_pub_registrar =
+      fl_plugin_registry_get_registrar_for_plugin(registry, "CommonPubPlugin");
+  common_pub_plugin_register_with_registrar(common_pub_registrar);
 }

+ 1 - 0
app_business/linux/flutter/generated_plugins.cmake

@@ -3,6 +3,7 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  common_pub
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST

+ 6 - 0
app_business/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,6 +5,12 @@
 import FlutterMacOS
 import Foundation
 
+import common_pub
+import path_provider_foundation
+import rive_common
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  CommonPubPlugin.register(with: registry.registrar(forPlugin: "CommonPubPlugin"))
+  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+  RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin"))
 }

+ 465 - 0
app_business/pubspec.lock

@@ -1,6 +1,22 @@
 # Generated by pub
 # See https://dart.dev/tools/pub/glossary#lockfile
 packages:
+  archive:
+    dependency: transitive
+    description:
+      name: archive
+      sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.4.9"
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.4.2"
   async:
     dependency: transitive
     description:
@@ -17,6 +33,22 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.1"
+  bubble:
+    dependency: transitive
+    description:
+      name: bubble
+      sha256: "65b992b8f8ba2e7e2871190cbdfaa0818b6de2f340bef37cb5ee1b61debe0226"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.1"
+  build_cli_annotations:
+    dependency: transitive
+    description:
+      name: build_cli_annotations
+      sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
   characters:
     dependency: transitive
     description:
@@ -41,6 +73,29 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.17.2"
+  common_pub:
+    dependency: transitive
+    description:
+      path: "../libs/common_pub"
+      relative: true
+    source: path
+    version: "0.0.1"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.1"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.3"
   cupertino_icons:
     dependency: "direct main"
     description:
@@ -49,6 +104,22 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.6"
+  equatable:
+    dependency: transitive
+    description:
+      name: equatable
+      sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.5"
+  f_cache:
+    dependency: transitive
+    description:
+      name: f_cache
+      sha256: "4470e60d9585a69392f568ed0a1b798dbae967f005a814b3e3402048f7292ede"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.1"
   fake_async:
     dependency: transitive
     description:
@@ -57,6 +128,30 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.3.1"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  fl_chart:
+    dependency: transitive
+    description:
+      name: fl_chart
+      sha256: c1e26c7e48496be85104c16c040950b0436674cdf0737f3f6e95511b2529b592
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.63.0"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -70,11 +165,101 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.0.3"
+  flutter_localizations:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_rust_bridge:
+    dependency: transitive
+    description:
+      name: flutter_rust_bridge
+      sha256: "7c5e94d037ccb0de7b5f7de3ff2491548d292b5aad01b01f5a5703f8aac9389b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.82.4"
   flutter_test:
     dependency: "direct dev"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  get:
+    dependency: "direct main"
+    description:
+      name: get
+      sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.6.6"
+  googleapis_auth:
+    dependency: transitive
+    description:
+      name: googleapis_auth
+      sha256: af7c3a3edf9d0de2e1e0a77e994fae0a581c525fa7012af4fa0d4a52ed9484da
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.4.1"
+  graphs:
+    dependency: transitive
+    description:
+      name: graphs
+      sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.3.1"
+  grpc:
+    dependency: transitive
+    description:
+      name: grpc
+      sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.2.4"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  http2:
+    dependency: transitive
+    description:
+      name: http2
+      sha256: "38db0c4aa9f1cd238a5d2e86aa0cc7cc91c77e0c6c94ba64bbe85e4ff732a952"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.0"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.0.2"
+  intl:
+    dependency: "direct main"
+    description:
+      name: intl
+      sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.18.1"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.6.7"
   lints:
     dependency: transitive
     description:
@@ -83,6 +268,22 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.1"
+  logger:
+    dependency: "direct main"
+    description:
+      name: logger
+      sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.2+1"
+  logging:
+    dependency: transitive
+    description:
+      name: logging
+      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
   matcher:
     dependency: transitive
     description:
@@ -107,6 +308,14 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.9.1"
+  mime:
+    dependency: transitive
+    description:
+      name: mime
+      sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.4"
   path:
     dependency: transitive
     description:
@@ -115,6 +324,150 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.8.3"
+  path_provider:
+    dependency: transitive
+    description:
+      name: path_provider
+      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.3.1"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  petitparser:
+    dependency: transitive
+    description:
+      name: petitparser
+      sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.0.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.3"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.7"
+  pointycastle:
+    dependency: transitive
+    description:
+      name: pointycastle
+      sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.7.3"
+  pool:
+    dependency: transitive
+    description:
+      name: pool
+      sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.5.1"
+  protobuf:
+    dependency: transitive
+    description:
+      name: protobuf
+      sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.0"
+  puppeteer:
+    dependency: transitive
+    description:
+      name: puppeteer
+      sha256: eedeaae6ec5d2e54f9ae22ab4d6b3dda2e8791c356cc783046d06c287ffe11d8
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.6.0"
+  rive:
+    dependency: "direct main"
+    description:
+      name: rive
+      sha256: fd15b219f5cc110285ebf52093b0b0f4038c3ca750f2fc5fc44d9c80a56c44f3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.3"
+  rive_common:
+    dependency: transitive
+    description:
+      name: rive_common
+      sha256: f4e20d0a99c5040c85624a3eb2b0b6b19e614d93a693c3bb25cf6e7bb2d3d6d3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.2.8"
+  shelf:
+    dependency: transitive
+    description:
+      name: shelf
+      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.4.1"
+  shelf_static:
+    dependency: transitive
+    description:
+      name: shelf_static
+      sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.2"
+  shelf_web_socket:
+    dependency: transitive
+    description:
+      name: shelf_web_socket
+      sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.4"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -128,6 +481,14 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.10.0"
+  sprintf:
+    dependency: transitive
+    description:
+      name: sprintf
+      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "7.0.0"
   stack_trace:
     dependency: transitive
     description:
@@ -168,6 +529,45 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.6.0"
+  track_common:
+    dependency: "direct main"
+    description:
+      path: "../libs/track_common"
+      relative: true
+    source: path
+    version: "1.0.0+1"
+  transparent_pointer:
+    dependency: transitive
+    description:
+      name: transparent_pointer
+      sha256: "27f5a7a63e517b6a56962bd473bbfcdcacce13fc996a264d6665da9a24650eb9"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.0"
+  tuple:
+    dependency: transitive
+    description:
+      name: tuple
+      sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.2"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.2"
+  uuid:
+    dependency: transitive
+    description:
+      name: uuid
+      sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.2.1"
   vector_math:
     dependency: transitive
     description:
@@ -184,5 +584,70 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.1.4-beta"
+  web_socket_channel:
+    dependency: transitive
+    description:
+      name: web_socket_channel
+      sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.4.0"
+  webview_flutter:
+    dependency: transitive
+    description:
+      name: webview_flutter
+      sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.4.2"
+  webview_flutter_android:
+    dependency: transitive
+    description:
+      name: webview_flutter_android
+      sha256: "8326ee235f87605a2bfc444a4abc897f4abc78d83f054ba7d3d1074ce82b4fbf"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.12.1"
+  webview_flutter_platform_interface:
+    dependency: transitive
+    description:
+      name: webview_flutter_platform_interface
+      sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.8.0"
+  webview_flutter_wkwebview:
+    dependency: transitive
+    description:
+      name: webview_flutter_wkwebview
+      sha256: accdaaa49a2aca2dc3c3230907988954cdd23fed0a19525d6c9789d380f4dc76
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.9.4"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "5.1.1"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.3"
+  yaml:
+    dependency: transitive
+    description:
+      name: yaml
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.2"
 sdks:
   dart: ">=3.1.5 <4.0.0"
+  flutter: ">=3.13.0"

+ 19 - 1
app_business/pubspec.yaml

@@ -35,6 +35,14 @@ dependencies:
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^1.0.2
+  track_common:
+    path: '../libs/track_common'
+  get: ^4.6.6
+  logger: ^2.0.2+1
+  flutter_localizations:
+    sdk: flutter
+  intl: any
+  rive: any
 
 dev_dependencies:
   flutter_test:
@@ -57,7 +65,7 @@ flutter:
   # included with your application, so that you can use the icons in
   # the material Icons class.
   uses-material-design: true
-
+  generate: true
   # To add assets to your application, add an assets section, like this:
   # assets:
   #   - images/a_dot_burr.jpeg
@@ -88,3 +96,13 @@ flutter:
   #
   # For details regarding fonts from package dependencies,
   # see https://flutter.dev/custom-fonts/#from-packages
+  assets:
+    - assets/images/
+
+
+
+flutter_assets:
+  assets_path: assets/
+  output_path: lib/generated/
+  filename: assets.dart
+  field_prefix:

+ 6 - 0
app_business/windows/flutter/generated_plugin_registrant.cc

@@ -6,6 +6,12 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <common_pub/common_pub_plugin_c_api.h>
+#include <rive_common/rive_plugin.h>
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
+  CommonPubPluginCApiRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("CommonPubPluginCApi"));
+  RivePluginRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("RivePlugin"));
 }

+ 2 - 0
app_business/windows/flutter/generated_plugins.cmake

@@ -3,6 +3,8 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  common_pub
+  rive_common
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST

+ 1 - 0
libs/common_pub

@@ -0,0 +1 @@
+Subproject commit 10f57487279eb9ea5a6072e46574f156a1733d48

+ 50 - 0
libs/track_common/.gitignore

@@ -0,0 +1,50 @@
+.DS_Store
+.dart_tool/
+
+.packages
+.pub/
+
+.idea/
+.vagrant/
+.sconsign.dblite
+.svn/
+
+migrate_working_dir/
+
+*.swp
+profile
+
+DerivedData/
+
+.generated/
+
+*.pbxuser
+*.mode1v3
+*.mode2v3
+*.perspectivev3
+
+!default.pbxuser
+!default.mode1v3
+!default.mode2v3
+!default.perspectivev3
+
+xcuserdata
+
+*.moved-aside
+
+*.pyc
+*sync/
+Icon?
+.tags*
+
+build/
+.android/
+.ios/
+.flutter-plugins
+.flutter-plugins-dependencies
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json

+ 10 - 0
libs/track_common/.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "d211f42860350d914a5ad8102f9ec32764dc6d06"
+  channel: "stable"
+
+project_type: module

+ 11 - 0
libs/track_common/README.md

@@ -0,0 +1,11 @@
+# track_common
+
+场控端公用。
+
+## Getting Started
+
+For help getting started with Flutter development, view the online
+[documentation](https://flutter.dev/).
+
+For instructions integrating Flutter modules to your existing applications,
+see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app).

+ 4 - 0
libs/track_common/analysis_options.yaml

@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

BIN
libs/track_common/assets/images/am_app_start_arrow.riv


BIN
libs/track_common/assets/images/bk_common_page.png


BIN
libs/track_common/assets/images/bk_login.png


BIN
libs/track_common/assets/images/bk_login_right.png


BIN
libs/track_common/assets/images/ic_cp.png


BIN
libs/track_common/assets/images/ic_location.png


BIN
libs/track_common/assets/images/ic_login_logo.png


BIN
libs/track_common/assets/images/ic_map_scale.png


BIN
libs/track_common/assets/images/ic_no_data.png


BIN
libs/track_common/assets/images/im_compass_no_map.png


+ 17 - 0
libs/track_common/lib/generated/assets.dart

@@ -0,0 +1,17 @@
+///This file is automatically generated. DO NOT EDIT, all your changes would be lost.
+class Assets {
+  Assets._();
+
+  static const String imagesAmAppStartArrow =
+      'assets/images/am_app_start_arrow.riv';
+  static const String imagesBkCommonPage = 'assets/images/bk_common_page.png';
+  static const String imagesBkLogin = 'assets/images/bk_login.png';
+  static const String imagesBkLoginRight = 'assets/images/bk_login_right.png';
+  static const String imagesIcCp = 'assets/images/ic_cp.png';
+  static const String imagesIcLocation = 'assets/images/ic_location.png';
+  static const String imagesIcLoginLogo = 'assets/images/ic_login_logo.png';
+  static const String imagesIcMapScale = 'assets/images/ic_map_scale.png';
+  static const String imagesIcNoData = 'assets/images/ic_no_data.png';
+  static const String imagesImCompassNoMap =
+      'assets/images/im_compass_no_map.png';
+}

+ 1 - 0
libs/track_common/lib/service.dart

@@ -0,0 +1 @@
+export 'service/all_init.dart';

+ 1 - 0
libs/track_common/lib/service/all_init.dart

@@ -0,0 +1 @@
+Future<void> allInit() async {}

+ 71 - 0
libs/track_common/lib/styles/color_schemes.g.dart

@@ -0,0 +1,71 @@
+import 'package:flutter/material.dart';
+
+const lightColorScheme = ColorScheme(
+  brightness: Brightness.light,
+  // primary: Color(0xFF00629E),
+  primary: Color(0xffffb40b),
+  onPrimary: Color(0xff000000),
+  primaryContainer: Color(0xfffdf6d4),
+  // onPrimaryContainer: Color(0xFF001D34),
+  onPrimaryContainer: Color(0xffff870d),
+  secondary: Color(0xff017dc7),
+  onSecondary: Color(0xFFFFFFFF),
+  secondaryContainer: Color(0xFFD6E4F7),
+  onSecondaryContainer: Color(0xff005d94),
+  tertiary: Color(0xFF695779),
+  onTertiary: Color(0xFFFFFFFF),
+  tertiaryContainer: Color(0xFFF0DBFF),
+  onTertiaryContainer: Color(0xFF241532),
+  error: Color(0xffff6203),
+  errorContainer: Color(0xFFFFDAD6),
+  onError: Color(0xFFFFFFFF),
+  onErrorContainer: Color(0xFF410002),
+  background: Color(0xffF0F0F0),
+  onBackground: Color(0xFF1A1C1E),
+  surface: Color(0xFFFCFCFF),
+  onSurface: Color(0xFF1A1C1E),
+  surfaceVariant: Color(0xFFDEE3EB),
+  onSurfaceVariant: Color(0xFF42474E),
+  outline: Color(0xFF73777F),
+  onInverseSurface: Color(0xFFF1F0F4),
+  inverseSurface: Color(0xFF2F3033),
+  inversePrimary: Color(0xFF9ACBFF),
+  shadow: Color(0xFF000000),
+  surfaceTint: Color(0xFF017dc7),
+  outlineVariant: Color(0xFFC2C7CF),
+  scrim: Color(0xFF000000),
+);
+
+const darkColorScheme = ColorScheme(
+  brightness: Brightness.dark,
+  primary: Color(0xFF9ACBFF),
+  onPrimary: Color(0xFF003355),
+  primaryContainer: Color(0xFF004A78),
+  onPrimaryContainer: Color(0xFFCFE5FF),
+  secondary: Color(0xFFBAC8DA),
+  onSecondary: Color(0xFF243240),
+  secondaryContainer: Color(0xFF3A4857),
+  onSecondaryContainer: Color(0xFFD6E4F7),
+  tertiary: Color(0xFFD4BEE6),
+  onTertiary: Color(0xFF392A49),
+  tertiaryContainer: Color(0xFF514060),
+  onTertiaryContainer: Color(0xFFF0DBFF),
+  error: Color(0xFFFFB4AB),
+  errorContainer: Color(0xFF93000A),
+  onError: Color(0xFF690005),
+  onErrorContainer: Color(0xFFFFDAD6),
+  background: Color(0xFF1A1C1E),
+  onBackground: Color(0xFFE2E2E5),
+  surface: Color(0xFF1A1C1E),
+  onSurface: Color(0xFFE2E2E5),
+  surfaceVariant: Color(0xFF42474E),
+  onSurfaceVariant: Color(0xFFC2C7CF),
+  outline: Color(0xFF8C9199),
+  onInverseSurface: Color(0xFF1A1C1E),
+  inverseSurface: Color(0xFFE2E2E5),
+  inversePrimary: Color(0xFF00629E),
+  shadow: Color(0xFF000000),
+  surfaceTint: Color(0xFF9ACBFF),
+  outlineVariant: Color(0xFF42474E),
+  scrim: Color(0xFF000000),
+);

+ 11 - 0
libs/track_common/lib/styles/theme.dart

@@ -0,0 +1,11 @@
+import 'package:flutter/material.dart';
+import 'color_schemes.g.dart';
+
+
+ThemeData appThemeData(){
+  return ThemeData(
+      useMaterial3: true,
+      colorScheme: lightColorScheme,
+      scaffoldBackgroundColor: const Color(0xffF0F0F0),
+  );
+}

+ 3 - 0
libs/track_common/lib/track_common.dart

@@ -0,0 +1,3 @@
+export 'package:common_pub/common_pub.dart';
+
+export 'styles/theme.dart';

+ 90 - 0
libs/track_common/lib/utils.dart

@@ -0,0 +1,90 @@
+import 'dart:io';
+
+import 'package:common_pub/common_pub.dart';
+import 'package:common_pub/pb.dart' as pb;
+import 'package:f_cache/manager.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:grpc/grpc.dart';
+import 'package:http/http.dart' as http;
+
+import 'styles/color_schemes.g.dart';
+import 'view/login/login_view.dart';
+
+Future<void> tryApi(
+  Future<void> Function() call, {
+  String? errTitle,
+  Future<bool> Function(GrpcError err)? onError,
+  Future<void> Function()? onSuccess,
+  VoidCallback? onFinally,
+}) async {
+  Future<bool> handleError(GrpcError err) async {
+    if (onError != null) {
+      return onError(err);
+    }
+    if (err.code == StatusCode.unauthenticated) {
+      if (await LoginView.to()) {
+        try {
+          await call();
+        } catch (e) {
+          Get.snackbar('出错了', '未知错误');
+        }
+      }
+      return true;
+    }
+
+    return false;
+  }
+
+  await tryCatchGrpc(
+    call,
+    onError: handleError,
+    onSuccess: onSuccess,
+    onFinally: onFinally,
+  );
+}
+
+class Preview extends StatelessWidget {
+  const Preview({super.key, required this.child});
+
+  final Widget child;
+
+  @override
+  Widget build(BuildContext context) {
+    return child;
+  }
+}
+
+typedef NetImage = pb.NetImage;
+
+extension NetImageExt on NetImage {
+  String? get md5Hex {
+    if (md5.isEmpty) {
+      return null;
+    } else {
+      return md5.toHexString();
+    }
+  }
+
+  Future<Reader> readerBuilder() async {
+    final url = Uri.parse(this.url);
+    var request = http.Request('GET', url);
+    var response = await request.send();
+    if (response.statusCode != 200) {
+      throw HttpException('state: ${response.statusCode}', uri: url);
+    }
+    final length = response.contentLength ?? 0;
+    return Reader(response.stream, length);
+  }
+
+  Future<void> preload() async {
+    await CacheManager()
+        .getCached(id: md5Hex ?? '', readerBuilder: readerBuilder);
+  }
+}
+
+void runPreview(Widget child) {
+  runApp(GetMaterialApp(
+      theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
+      home: Preview(child: child)));
+}

+ 3 - 0
libs/track_common/lib/view.dart

@@ -0,0 +1,3 @@
+export 'view/init_view.dart';
+export 'view/login/login_controller.dart';
+export 'view/login/login_view.dart';

+ 71 - 0
libs/track_common/lib/view/init_view.dart

@@ -0,0 +1,71 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:track_common/view/login/login_view.dart';
+
+abstract class InitController extends GetxController {
+  Future<bool> isNeedLogin();
+
+  Future<void> allInit();
+
+  final _use = true.obs;
+
+  @override
+  void onInit() {
+    super.onInit();
+    init();
+  }
+
+  Future<void> init() async {
+    await allInit();
+    if (await isNeedLogin()) {
+      Get.offNamed(LoginView.name);
+    }
+  }
+}
+
+class InitView extends GetView<InitController> {
+  const InitView({super.key});
+
+  static const name = '/InitView';
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+        body: Obx(() => Text('${controller._use}',
+            style: const TextStyle(color: Colors.transparent))));
+  }
+}
+
+// class _State extends State<InitView> {
+//   @override
+//   Widget build(BuildContext context) {
+//     return const Scaffold(body: Center());
+//   }
+//
+//   void init() async {
+//     await allInit();
+//     await 1.seconds.delay();
+//
+//
+//
+//
+//     try {
+//
+//       await api.ApiService.to.stub.toMapListV2(api.MapListRequestV2());
+//       Get.offAll(() => const HomeView(), binding: HomeView.bindings());
+//     } catch (e) {
+//       LoginView.to(
+//           canBack: false,
+//           thenToPageCall: () {
+//             Get.offAll(() => const HomeView(), binding: HomeView.bindings());
+//           });
+//     }
+//   }
+//
+//   @override
+//   void initState() {
+//     super.initState();
+//
+//     init();
+//   }
+// }

+ 132 - 0
libs/track_common/lib/view/login/common.dart

@@ -0,0 +1,132 @@
+import 'package:common_pub/common_pub.dart';
+
+import '../../generated/assets.dart';
+import '../../widget.dart';
+
+class AppTopBar extends StatelessWidget implements PreferredSizeWidget {
+  const AppTopBar(
+      {super.key,
+      required this.title,
+      required this.hasBackText,
+      required this.height});
+
+  final double height;
+  final String title;
+  final bool hasBackText;
+
+  Widget bkText(
+    String text,
+    double fontSizeRpx,
+    double alpha,
+    BuildContext context,
+    double xP,
+    double yP,
+  ) {
+    return Positioned(
+        left: context.width * xP,
+        top: height * yP,
+        child: Text(text,
+            style: TextStyle(
+              color: const Color(0xFFade0ff).withAlpha((alpha * 255).round()),
+              fontWeight: FontWeight.w500,
+              fontSize: context.wp(fontSizeRpx),
+            )));
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final children = <Widget>[];
+    if (hasBackText) {
+      children.addAll([
+        bkText('Orienting', 47.92, 0.6, context, 0.1, 0.2),
+        bkText('定目标', 37.5, 0.58, context, 0.7, 0.18),
+        bkText('Targeting', 56.25, 0.2, context, 0.52, 0.26),
+        bkText('定向', 54.17, 0.6, context, 0.3, 0.33),
+        bkText('定位', 31.25, 0.5, context, 0.08, 0.4),
+        bkText('Locating', 45.83, 0.4, context, 0.12, 0.52),
+        bkText('到达目标', 37.5, 0.5, context, 0.53, 0.48),
+        bkText('Reaching', 33.33, 0.5, context, 0.6, 0.6),
+      ]);
+    }
+
+    children.add(Positioned(
+        left: context.wp(54.17),
+        bottom: context.wp(58.33),
+        child: Text(title,
+            style: TextStyle(
+              color: Colors.white,
+              fontSize: context.wp(58.33),
+              fontWeight: FontWeight.w400,
+            ))));
+
+    return Container(
+      width: double.infinity,
+      height: height,
+      decoration: const BoxDecoration(
+          image: DecorationImage(
+              image: AssetImage(Assets.imagesBkLogin),
+              alignment: Alignment.topCenter,
+              fit: BoxFit.fitWidth)),
+      child: Stack(
+        children: children,
+      ),
+    );
+  }
+
+  @override
+  Size get preferredSize => Size.fromHeight(height);
+}
+
+Widget button(BuildContext context, String text, VoidCallback onPressed) {
+  return SizedBox(
+      width: double.infinity,
+      height: context.wp(3.19),
+      child: FilledButton(
+          style: FilledButton.styleFrom(
+              backgroundColor: const Color(0xffffb40b),
+              shape: RoundedRectangleBorder(
+                  borderRadius: BorderRadius.circular(context.wp(0.42)))),
+          onPressed: onPressed,
+          child: Text(
+            text,
+            style: const TextStyle(color: Colors.black, fontSize: 15),
+          )));
+}
+
+class TextDecoration extends InputDecoration {
+  const TextDecoration({required String hintText})
+      : super(
+          hintText: hintText,
+          border: const OutlineInputBorder(),
+          isDense: true,
+        );
+}
+
+class GetCodeButton extends StatelessWidget {
+  final Duration codeRetryLeft;
+  final VoidCallback onPressed;
+
+  const GetCodeButton(
+      {super.key, required this.codeRetryLeft, required this.onPressed});
+
+  @override
+  Widget build(BuildContext context) {
+    final isEnable = codeRetryLeft.inSeconds <= 0;
+    final onPressed = isEnable ? this.onPressed : () {};
+
+    final bkColor =
+        isEnable ? const Color(0xffefefef) : const Color(0xffc2c2c2);
+    final foregroundColor = isEnable ? Colors.black : Colors.white;
+    final text = isEnable ? '获取验证码' : '请稍后(${codeRetryLeft.inSeconds})';
+
+    return ElevatedButton(
+        onPressed: onPressed,
+        style: ElevatedButton.styleFrom(
+            backgroundColor: bkColor,
+            shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(2.0)),
+            foregroundColor: foregroundColor,
+            padding: EdgeInsets.zero),
+        child: Text(text));
+  }
+}

+ 133 - 0
libs/track_common/lib/view/login/login_controller.dart

@@ -0,0 +1,133 @@
+import 'dart:async';
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:grpc/grpc.dart';
+import 'package:track_common/track_common.dart';
+
+import '../../utils.dart';
+
+abstract class LoginController extends GetxController {
+  final phone = "".obs;
+  final password = "".obs;
+  final codeRetryLeft = 0.seconds.obs;
+  Timer? ticker;
+  var isSignInEnable = true;
+  final isAgreeContract = false.obs;
+
+  Future<Duration> getCodeLifeTime(String phone);
+  Future<void> authSendCodeToPhone(String phone);
+  Future<void> signIn(String phone, String code);
+
+  @override
+  void onInit() {
+    super.onInit();
+
+    ticker = Timer.periodic(1.seconds, (timer) {
+      codeRetryLeft.value -= 1.seconds;
+    });
+  }
+
+  void onGetCode() async {
+    info("获取验证码");
+
+    await tryApi(
+        () async {
+          codeRetryLeft.value = await getCodeLifeTime(phone.value);
+          if (codeRetryLeft.value.inSeconds > 0) {
+            return;
+          }
+          await authSendCodeToPhone(phone.value);
+          codeRetryLeft.value = await getCodeLifeTime(phone.value);
+          info("获取验证码结束");
+        },
+        errTitle: '获取验证码失败',
+        onError: (e) async {
+          if (e.code == StatusCode.notFound) {
+            Get.snackbar('用户未注册', "请先注册",
+                isDismissible: true, duration: 3.seconds);
+            return true;
+          }
+
+          return false;
+        });
+  }
+
+  Future<void> onSignIn() async {
+    // if (!isAgreeContract.value) {
+    //   Get.snackbar('请先', '阅读并同意协议');
+    //   return;
+    // }
+
+    if (!isSignInEnable) {
+      return;
+    }
+    try {
+      isSignInEnable = false;
+
+      if (phone.value.isEmpty) {
+        Get.snackbar('手机号错误', "请重新输入");
+        return;
+      }
+      if (password.value.isEmpty) {
+        Get.snackbar('验证码错误', "请重新输入");
+        return;
+      }
+
+      await tryApi(
+          () async {
+            info("登录 ${phone.value} ${password.value}");
+            await signIn(phone.value, password.value);
+            final call = Get.arguments;
+            info("登录成功");
+            if (call is VoidCallback) {
+              call();
+            } else {
+              Get.back(result: true, closeOverlays: true);
+            }
+          },
+          errTitle: '登录失败',
+          onError: (e) async {
+            switch (e.code) {
+              case StatusCode.unauthenticated:
+                Get.snackbar('登录失败', "验证码错误");
+                return true;
+              case StatusCode.notFound:
+                Get.snackbar('用户未注册', "请先注册");
+                return true;
+
+              default:
+                return false;
+            }
+          });
+    } finally {
+      isSignInEnable = true;
+    }
+  }
+
+  @override
+  void onClose() {
+    ticker?.cancel();
+  }
+}
+
+class LoginControllerMock extends LoginController {
+  @override
+  Future<void> authSendCodeToPhone(String phone) {
+    // TODO: implement authSendCodeToPhone
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<Duration> getCodeLifeTime(String phone) {
+    // TODO: implement getCodeLifeTime
+    throw UnimplementedError();
+  }
+
+  @override
+  Future<void> signIn(String phone, String code) {
+    // TODO: implement signIn
+    throw UnimplementedError();
+  }
+}

+ 415 - 0
libs/track_common/lib/view/login/login_view.dart

@@ -0,0 +1,415 @@
+import 'package:common_pub/screen.dart';
+import 'package:common_pub/utils.dart';
+import 'package:flutter/gestures.dart';
+import 'package:rive/rive.dart';
+import 'package:track_common/widget/prelude.dart';
+
+import 'common.dart';
+import 'login_controller.dart';
+
+class LoginView extends GetView<LoginController> {
+  static const name = '/LoginView';
+
+  const LoginView({super.key});
+
+  static Future<bool> to({
+    bool canBack = true,
+    VoidCallback? thenToPageCall,
+  }) async {
+    Future<dynamic>? r;
+    if (canBack) {
+      r = Get.to(LoginView.name, arguments: thenToPageCall);
+    } else {
+      r = Get.offAll(() => LoginView.name, arguments: thenToPageCall);
+    }
+
+    if (r != null) {
+      final r2 = await r;
+      if (r2 is bool) {
+        return r2;
+      }
+    }
+    return false;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      // appBar: AppTopBar(title: '登录账号', hasBackText: true, height: context.height*0.3),
+      backgroundColor: Colors.white,
+      body: Container(
+        height: double.infinity,
+        decoration: const BoxDecoration(color: Colors.white),
+        alignment: Alignment.center,
+        clipBehavior: Clip.hardEdge,
+        child: Row(
+          children: [
+            const Expanded(
+              flex: 2,
+              child: AnimationPage(),
+            ),
+            Expanded(
+              flex: 3,
+              child: wPageRight(context),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget wPageRight(BuildContext context) {
+    var inputHeight = context.height * 0.45;
+    const inputMinHeight = 260.0;
+    if (inputHeight < inputMinHeight) {
+      inputHeight = inputMinHeight;
+    }
+
+    return Container(
+        // margin: EdgeInsets.fromLTRB(context.width*(6), context.width*5.6), context.width*(6), context.width*(2)),
+        padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
+        decoration: const BoxDecoration(
+          // color: Color(0xffffcb00),
+          image: DecorationImage(
+              image: AssetImage(Assets.imagesBkLoginRight, package: package),
+              alignment: Alignment.topCenter,
+              fit: BoxFit.fitWidth),
+        ),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            const Expanded(
+                child: Text(
+              '定向运动活动现场监控系统',
+              textAlign: TextAlign.center,
+              style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold),
+            )),
+            // SizedBox(height: inputHeight),
+            // Expanded(child: wInput(context)),
+            SizedBox(height: inputHeight, child: wInput(context)),
+            Expanded(
+                child: Image.asset(Assets.imagesIcLoginLogo, package: package)),
+            // Expanded(flex: 10,child:  wExtra()),
+          ],
+        ));
+  }
+
+  InputDecoration wInputDecoration(hintText) {
+    return InputDecoration(
+      // isCollapsed: true,
+      contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
+      hintText: hintText,
+      // hintStyle: TextStyle(fontSize: 12.0.rpx),
+      focusedBorder: OutlineInputBorder(
+        borderRadius: BorderRadius.circular(4.0),
+        borderSide: const BorderSide(
+          color: Colors.blue,
+          width: 1.0,
+        ),
+      ),
+      enabledBorder: OutlineInputBorder(
+        borderRadius: BorderRadius.circular(4.0),
+        borderSide: const BorderSide(
+          color: Color(0xffaaaaaa),
+          width: 1.0,
+        ),
+      ),
+    );
+  }
+
+  Widget wInput(BuildContext context) {
+    return Container(
+        margin: EdgeInsets.fromLTRB(
+            context.wp(6), context.wp(3), context.wp(6), context.wp(2)),
+        padding: EdgeInsets.fromLTRB(
+            context.wp(6), context.wp(3.6), context.wp(6), context.wp(2)),
+        decoration: BoxDecoration(
+          color: const Color(0xffffffff),
+          borderRadius: BorderRadius.circular(context.wp(1.0)),
+          boxShadow: const [
+            BoxShadow(
+                color: Color(0x38000000),
+                offset: Offset(0.0, 3.0),
+                blurRadius: 6)
+          ],
+        ),
+        child: Column(
+          children: [
+            // const Spacer(flex: 20),
+            TextFormField(
+                decoration: wInputDecoration('请输入手机号'),
+                validator: (String? value) {
+                  if (value == null || !value.isPhoneNumber) {
+                    return '请输入正确的手机号';
+                  }
+                  return null;
+                },
+                onChanged: (value) {
+                  controller.phone.value = value;
+                },
+                keyboardType: TextInputType.phone),
+            const Spacer(flex: 50),
+            Stack(
+              alignment: Alignment.centerRight,
+              children: [
+                TextFormField(
+                  decoration: wInputDecoration('请输入验证码'),
+                  onChanged: (value) {
+                    controller.password.value = value;
+                  },
+                  keyboardType: TextInputType.number,
+                ),
+                Padding(
+                  padding: const EdgeInsets.only(right: 4),
+                  child: SizedBox(
+                    width: 84,
+                    height: 37,
+                    child: Obx(() => GetCodeButton(
+                          codeRetryLeft: controller.codeRetryLeft.value,
+                          onPressed: () => controller.onGetCode(),
+                        )),
+                  ),
+                ),
+              ],
+            ),
+            // _TextContract(),
+            const Spacer(flex: 80),
+            button(
+              context,
+              '登    录',
+              () => controller.onSignIn(),
+            ),
+            const Spacer(flex: 10),
+          ],
+        ));
+  }
+
+  Widget wExtra() {
+    return Padding(
+        padding: const EdgeInsets.only(left: 41.67, right: 41.67),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Row(
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                divider(),
+                const Padding(
+                    padding: EdgeInsets.only(left: 22.9, right: 22.9),
+                    child: Text(
+                      '其他登录方式',
+                      style: TextStyle(fontSize: 25.0),
+                    )),
+                divider(),
+              ],
+            ),
+            const SizedBox(height: 76.5),
+            const Row(),
+            const Spacer(),
+            Text.rich(TextSpan(
+                text: '还不是我们的会员?',
+                style: const TextStyle(fontSize: 33.33, color: Colors.black),
+                children: [
+                  TextSpan(
+                    text: '点击注册',
+                    style: const TextStyle(color: Color(0xffffb40b)),
+                    recognizer: TapGestureRecognizer()
+                      ..onTap = () {
+                        // SignUpView.show();
+                      },
+                  ),
+                ])),
+            const SizedBox(height: 76.5),
+          ],
+        ));
+  }
+
+  Widget divider() {
+    return Expanded(
+        child: Container(
+      height: 2.0,
+      color: Colors.black,
+    ));
+  }
+}
+
+final _duration = 2.seconds;
+
+class AnimationPage extends StatefulWidget {
+  const AnimationPage({super.key});
+
+  @override
+  State<StatefulWidget> createState() {
+    return _AnimationPageState();
+  }
+}
+
+class _AnimationPageState extends State<AnimationPage>
+    with SingleTickerProviderStateMixin {
+  late Animation<double> animation;
+  late AnimationController animationController;
+
+  @override
+  void initState() {
+    super.initState();
+    animationController = AnimationController(duration: _duration, vsync: this);
+    animation = Tween<double>(begin: 0, end: 1).animate(animationController);
+    animationController.forward();
+  }
+
+  @override
+  void dispose() {
+    animationController.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return wPageLeft(context);
+  }
+
+  Widget wPageLeft(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
+      decoration: const BoxDecoration(
+          image: DecorationImage(
+              image: AssetImage(Assets.imagesBkCommonPage, package: package),
+              fit: BoxFit.cover)),
+      child: Column(
+        children: [
+          Expanded(
+              flex: 1,
+              child: Container(
+                // color: const Color(0xffffcb00),
+                padding: const EdgeInsets.only(bottom: 32),
+                alignment: Alignment.bottomCenter,
+                child: Stack(
+                  alignment: Alignment.center,
+                  children: [
+                    Image.asset(
+                      Assets.imagesImCompassNoMap,
+                      height: context.wp(15.0),
+                      fit: BoxFit.fitHeight,
+                      package: package,
+                    ),
+                    SizedBox(
+                        height: context.wp(10.0),
+                        child: const RiveAnimation.asset(
+                          'packages/$package/${Assets.imagesAmAppStartArrow}',
+                          fit: BoxFit.fitHeight,
+                        ))
+                  ],
+                ),
+              )),
+          Expanded(
+              flex: 1,
+              child: Column(
+                // mainAxisAlignment: MainAxisAlignment.start,
+                children: [
+                  AnimatedText(animation: animation),
+                  Expanded(
+                      child: Stack(
+                    alignment: Alignment.center,
+                    children: [
+                      Center(
+                        child: AnimatedColors(
+                          animation: animation,
+                        ),
+                      ),
+                      // Positioned(
+                      //     bottom: 2.6.width*,
+                      //     child:
+                      //     Image.asset(Assets.imagesIcLogo, height: 5.0.width*))
+                    ],
+                  ))
+                ],
+              )),
+        ],
+      ),
+    );
+  }
+}
+
+class AnimatedText extends AnimatedWidget {
+  const AnimatedText({super.key, required Animation<double> animation})
+      : super(listenable: animation);
+
+  @override
+  Widget build(BuildContext context) {
+    final animation = listenable as Animation<double>;
+    var style = (context.textTheme.titleLarge ?? const TextStyle()).copyWith(
+        height: context.wp(0.14),
+        color: Colors.white,
+        fontSize: context.wp(2.2));
+
+    return Opacity(
+        opacity: animation.value,
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            SizedBox(
+              height: context.wp(0.9),
+            ),
+            Text('确定方向                ', style: style),
+            Text('              发现你自己的路!', style: style),
+            Text('Orienting, Discover Your Own Way!',
+                style: style.copyWith(
+                    color: const Color(0xffade0ff),
+                    fontWeight: FontWeight.bold,
+                    fontSize: context.wp(1.4))),
+          ],
+        ));
+  }
+}
+
+class AnimatedColors extends AnimatedWidget {
+  const AnimatedColors({super.key, required Animation<double> animation})
+      : super(listenable: animation);
+
+  @override
+  Widget build(BuildContext context) {
+    final animation = listenable as Animation<double>;
+    var style = (context.textTheme.titleLarge ?? const TextStyle())
+        .copyWith(color: Colors.white, fontSize: context.wp(8.33));
+
+    var children = <Widget>[];
+
+    for (var i = 0; i < hrPColors.length; i++) {
+      final color = hrPColors[i];
+      var opacity = 0.0;
+      if (i < animation.value * hrPColors.length) {
+        opacity = 1;
+      }
+
+      children.add(Opacity(
+          opacity: opacity,
+          child: Container(
+            width: context.wp(1.02),
+            decoration: BoxDecoration(
+                color: color,
+                borderRadius: BorderRadius.circular(context.wp(2.0)),
+                border: Border.all(color: Colors.white.withAlpha(100))),
+          )));
+    }
+
+    return Column(
+      mainAxisSize: MainAxisSize.min,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        SizedBox(height: context.wp(5.36)),
+        SizedBox(
+            width: context.wp(7.6),
+            height: context.wp(2.5),
+            child: Row(
+              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+              children: children,
+            )),
+        // Text('支持心率带检测身体数据',
+        //     style: style.copyWith(
+        //         color: const Color(0xffffcb00), fontSize: 3.3.width*)),
+      ],
+    );
+  }
+}

+ 98 - 0
libs/track_common/lib/view/login/logo_widget.dart

@@ -0,0 +1,98 @@
+import 'package:track_common/widget/prelude.dart';
+
+class LogoWidget extends StatelessWidget {
+  const LogoWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return SizedBox(
+      width: double.infinity,
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        children: [
+          const SizedBox(height: 60),
+          Image.asset(Assets.imagesIcLoginLogo, package: package, height: 54),
+          const SizedBox(
+            height: 23,
+          )
+        ],
+      ),
+    );
+  }
+}
+
+class TextDecoration extends InputDecoration {
+  const TextDecoration({required String hintText})
+      : super(
+          hintText: hintText,
+          border: const OutlineInputBorder(),
+          isDense: true,
+        );
+}
+
+class GetCodeButton extends StatelessWidget {
+  final Duration codeRetryLeft;
+  final VoidCallback onPressed;
+
+  const GetCodeButton(
+      {super.key, required this.codeRetryLeft, required this.onPressed});
+
+  @override
+  Widget build(BuildContext context) {
+    final isEnable = codeRetryLeft.inSeconds <= 0;
+    final onPressed = isEnable ? this.onPressed : () {};
+
+    final bkColor =
+        isEnable ? const Color(0xff19be30) : const Color(0xffc2c2c2);
+    final foregroundColor = isEnable ? Colors.white : Colors.white;
+    final text = isEnable ? '获取验证码' : '请稍后(${codeRetryLeft.inSeconds})';
+
+    return ElevatedButton(
+        onPressed: onPressed,
+        style: ElevatedButton.styleFrom(
+            backgroundColor: bkColor,
+            shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(2.0)),
+            foregroundColor: foregroundColor,
+            padding: EdgeInsets.zero),
+        child: Text(text));
+  }
+}
+
+class SignInButton extends StatelessWidget {
+  final double? height;
+  final double? width;
+  final VoidCallback? onPressed;
+  final Widget? child;
+  final Color color1;
+  final Color color2;
+
+  const SignInButton({
+    super.key,
+    required this.onPressed,
+    required this.child,
+    required this.color1,
+    required this.color2,
+    this.width,
+    this.height,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return GestureDetector(
+        onTap: onPressed,
+        child: Container(
+          height: height,
+          width: width,
+          alignment: Alignment.center,
+          decoration: BoxDecoration(
+              gradient: LinearGradient(colors: [
+                color1,
+                color2,
+              ]),
+              borderRadius: BorderRadius.circular(6.0)),
+          child: child,
+        ));
+  }
+}

+ 6 - 0
libs/track_common/lib/widget.dart

@@ -0,0 +1,6 @@
+export 'package:flutter/material.dart';
+// export 'generated/assets.dart';
+export 'package:get/get.dart';
+
+// export 'widget/app_net_image.dart';
+export 'widget/title_point.dart';

+ 6 - 0
libs/track_common/lib/widget/prelude.dart

@@ -0,0 +1,6 @@
+export 'package:flutter/material.dart';
+export 'package:get/get.dart';
+
+export '../generated/assets.dart';
+
+const package = 'track_common';

+ 16 - 0
libs/track_common/lib/widget/title_point.dart

@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+
+
+class TitlePoint extends StatelessWidget{
+  const TitlePoint({super.key, this.color = Colors.blue});
+
+  final Color color;
+
+  @override
+  Widget build(BuildContext context) {
+    return CircleAvatar(
+        backgroundColor: color,
+        radius: 5);
+  }
+
+}

+ 633 - 0
libs/track_common/pubspec.lock

@@ -0,0 +1,633 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  archive:
+    dependency: transitive
+    description:
+      name: archive
+      sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.4.9"
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.4.2"
+  async:
+    dependency: transitive
+    description:
+      name: async
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.11.0"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  bubble:
+    dependency: transitive
+    description:
+      name: bubble
+      sha256: "65b992b8f8ba2e7e2871190cbdfaa0818b6de2f340bef37cb5ee1b61debe0226"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.1"
+  build_cli_annotations:
+    dependency: transitive
+    description:
+      name: build_cli_annotations
+      sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.1"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.17.2"
+  common_pub:
+    dependency: "direct main"
+    description:
+      path: "../common_pub"
+      relative: true
+    source: path
+    version: "0.0.1"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.1"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.0.3"
+  cupertino_icons:
+    dependency: "direct main"
+    description:
+      name: cupertino_icons
+      sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.6"
+  equatable:
+    dependency: transitive
+    description:
+      name: equatable
+      sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.5"
+  f_cache:
+    dependency: "direct main"
+    description:
+      name: f_cache
+      sha256: "4470e60d9585a69392f568ed0a1b798dbae967f005a814b3e3402048f7292ede"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.1"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.1"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.0"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  fl_chart:
+    dependency: transitive
+    description:
+      name: fl_chart
+      sha256: c1e26c7e48496be85104c16c040950b0436674cdf0737f3f6e95511b2529b592
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.63.0"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.3"
+  flutter_rust_bridge:
+    dependency: transitive
+    description:
+      name: flutter_rust_bridge
+      sha256: "7c5e94d037ccb0de7b5f7de3ff2491548d292b5aad01b01f5a5703f8aac9389b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.82.4"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  get:
+    dependency: "direct main"
+    description:
+      name: get
+      sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.6.6"
+  googleapis_auth:
+    dependency: transitive
+    description:
+      name: googleapis_auth
+      sha256: af7c3a3edf9d0de2e1e0a77e994fae0a581c525fa7012af4fa0d4a52ed9484da
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.4.1"
+  graphs:
+    dependency: transitive
+    description:
+      name: graphs
+      sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.3.1"
+  grpc:
+    dependency: "direct main"
+    description:
+      name: grpc
+      sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.2.4"
+  http:
+    dependency: "direct main"
+    description:
+      name: http
+      sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
+  http2:
+    dependency: transitive
+    description:
+      name: http2
+      sha256: "38db0c4aa9f1cd238a5d2e86aa0cc7cc91c77e0c6c94ba64bbe85e4ff732a952"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.0"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.0.2"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.6.7"
+  lints:
+    dependency: transitive
+    description:
+      name: lints
+      sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  logger:
+    dependency: transitive
+    description:
+      name: logger
+      sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.2+1"
+  logging:
+    dependency: transitive
+    description:
+      name: logging
+      sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.16"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.5.0"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.9.1"
+  mime:
+    dependency: transitive
+    description:
+      name: mime
+      sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.4"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.8.3"
+  path_provider:
+    dependency: transitive
+    description:
+      name: path_provider
+      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.3.1"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.2.1"
+  petitparser:
+    dependency: transitive
+    description:
+      name: petitparser
+      sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.0.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.3"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.7"
+  pointycastle:
+    dependency: transitive
+    description:
+      name: pointycastle
+      sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.7.3"
+  pool:
+    dependency: transitive
+    description:
+      name: pool
+      sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.5.1"
+  protobuf:
+    dependency: transitive
+    description:
+      name: protobuf
+      sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.0"
+  puppeteer:
+    dependency: transitive
+    description:
+      name: puppeteer
+      sha256: eedeaae6ec5d2e54f9ae22ab4d6b3dda2e8791c356cc783046d06c287ffe11d8
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.6.0"
+  rive:
+    dependency: "direct main"
+    description:
+      name: rive
+      sha256: fd15b219f5cc110285ebf52093b0b0f4038c3ca750f2fc5fc44d9c80a56c44f3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.12.3"
+  rive_common:
+    dependency: transitive
+    description:
+      name: rive_common
+      sha256: f4e20d0a99c5040c85624a3eb2b0b6b19e614d93a693c3bb25cf6e7bb2d3d6d3
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.2.8"
+  shelf:
+    dependency: transitive
+    description:
+      name: shelf
+      sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.4.1"
+  shelf_static:
+    dependency: transitive
+    description:
+      name: shelf_static
+      sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.2"
+  shelf_web_socket:
+    dependency: transitive
+    description:
+      name: shelf_web_socket
+      sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.4"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.10.0"
+  sprintf:
+    dependency: transitive
+    description:
+      name: sprintf
+      sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "7.0.0"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.11.0"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.1"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.6.0"
+  transparent_pointer:
+    dependency: transitive
+    description:
+      name: transparent_pointer
+      sha256: "27f5a7a63e517b6a56962bd473bbfcdcacce13fc996a264d6665da9a24650eb9"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.0"
+  tuple:
+    dependency: transitive
+    description:
+      name: tuple
+      sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.2"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.2"
+  uuid:
+    dependency: transitive
+    description:
+      name: uuid
+      sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.2.1"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.4"
+  web:
+    dependency: transitive
+    description:
+      name: web
+      sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.1.4-beta"
+  web_socket_channel:
+    dependency: transitive
+    description:
+      name: web_socket_channel
+      sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.4.0"
+  webview_flutter:
+    dependency: transitive
+    description:
+      name: webview_flutter
+      sha256: "42393b4492e629aa3a88618530a4a00de8bb46e50e7b3993fedbfdc5352f0dbf"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.4.2"
+  webview_flutter_android:
+    dependency: transitive
+    description:
+      name: webview_flutter_android
+      sha256: "8326ee235f87605a2bfc444a4abc897f4abc78d83f054ba7d3d1074ce82b4fbf"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.12.1"
+  webview_flutter_platform_interface:
+    dependency: transitive
+    description:
+      name: webview_flutter_platform_interface
+      sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.8.0"
+  webview_flutter_wkwebview:
+    dependency: transitive
+    description:
+      name: webview_flutter_wkwebview
+      sha256: accdaaa49a2aca2dc3c3230907988954cdd23fed0a19525d6c9789d380f4dc76
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.9.4"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "5.1.1"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.0.3"
+  yaml:
+    dependency: transitive
+    description:
+      name: yaml
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.2"
+sdks:
+  dart: ">=3.1.5 <4.0.0"
+  flutter: ">=3.13.0"

+ 93 - 0
libs/track_common/pubspec.yaml

@@ -0,0 +1,93 @@
+name: track_common
+description: 场控端公用。
+publish_to: 'none'
+
+# 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 used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+#
+# This version is used _only_ for the Runner app, which is used if you just do
+# a `flutter run` or a `flutter make-host-app-editable`. It has no impact
+# on any other native host app that you embed your Flutter project into.
+version: 1.0.0+1
+
+environment:
+  sdk: '>=3.1.5 <4.0.0'
+
+dependencies:
+  flutter:
+    sdk: flutter
+  get: any
+  # The following adds the Cupertino Icons font to your application.
+  # Use with the CupertinoIcons class for iOS style icons.
+  cupertino_icons: ^1.0.2
+  common_pub:
+    path: '../common_pub'
+  grpc: ^3.2.4
+  http: ^1.1.0
+  f_cache: ^3.1.1
+  rive: ^0.12.3
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+  flutter_lints: ^2.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+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.
+  uses-material-design: true
+
+  # To add Flutter specific 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 Flutter specific 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
+
+  assets:
+    - assets/images/
+
+flutter_assets:
+  assets_path: assets/
+  output_path: lib/generated/
+  filename: assets.dart
+  field_prefix:
+
+

+ 12 - 0
libs/track_common/test/widget_test.dart

@@ -0,0 +1,12 @@
+// This is a basic Flutter widget test.
+//
+// To perform an interaction with a widget in your test, use the WidgetTester
+// utility in the flutter_test package. For example, you can send tap and scroll
+// gestures. You can also use WidgetTester to find child widgets in the widget
+// tree, read text, and verify that the values of widget properties are correct.
+
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  testWidgets('Counter increments smoke test', (WidgetTester tester) async {});
+}