周睿 hace 2 años
padre
commit
851ad3a7bc

BIN
assets/images/am_app_start_arrow.riv


BIN
assets/images/bk_common_page.png


BIN
assets/images/bk_login.png


BIN
assets/images/bk_login_right.png


BIN
assets/images/ic_login_logo.png


BIN
assets/images/im_compass_no_map.png


+ 15 - 0
lib/bindings.dart

@@ -0,0 +1,15 @@
+import 'package:get/get.dart';
+import 'view/login/login_view.dart';
+import 'route.dart';
+
+
+class AppBindings{
+  static List<GetPage<dynamic>> getPages(){
+    return [
+      GetPage(
+          name: RouteName.signIn,
+          page: () => const LoginView(),
+          binding: LoginView.bindings()),
+    ];
+  }
+}

+ 12 - 0
lib/generated/assets.dart

@@ -0,0 +1,12 @@
+///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 imagesIcLoginLogo = 'assets/images/ic_login_logo.png';
+  static const String imagesImCompassNoMap = 'assets/images/im_compass_no_map.png';
+
+}

+ 36 - 0
lib/logger.dart

@@ -0,0 +1,36 @@
+import 'package:logger/logger.dart';
+
+
+const level = Level.debug;
+
+final _logger = Logger(
+    printer: PrettyPrinter(
+        stackTraceBeginIndex: 1,
+        methodCount: 2
+    ),
+    level: level
+);
+final _loggerNoStack = Logger(
+  printer: PrettyPrinter(
+      methodCount: 0,
+    printTime: true
+  ),
+    level: level
+);
+
+
+void debug(dynamic message, [dynamic error, StackTrace? stackTrace]){
+  _logger.d(message, error:error, stackTrace:stackTrace);
+}
+
+void info(dynamic message, [dynamic error, StackTrace? stackTrace]){
+  _loggerNoStack.i(message, error:error, stackTrace:stackTrace);
+}
+
+void warn(dynamic message, [dynamic error, StackTrace? stackTrace]){
+  _logger.w(message, error:error, stackTrace:stackTrace);
+}
+
+void error(dynamic message, [dynamic error, StackTrace? stackTrace]){
+  _logger.e(message, error:error, stackTrace:stackTrace);
+}

+ 12 - 118
lib/main.dart

@@ -1,125 +1,19 @@
 import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:track_offical/view/init_view.dart';
+import 'styles/theme.dart';
 
-void main() {
-  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();
+void main() {
+  WidgetsFlutterBinding.ensureInitialized();
+  runApp(GetMaterialApp(
+    debugShowCheckedModeBanner: true,
+    title: '小飞龙定向场控',
+    theme: appThemeData(),
+    darkTheme: appThemeData(),
+    home: const InitView(),
+  ));
 }
 
-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.
-    );
-  }
-}

+ 22 - 0
lib/route.dart

@@ -0,0 +1,22 @@
+import 'package:flutter/foundation.dart';
+import 'package:get/get.dart';
+
+class RouteName {
+  static const init = '/init';
+  static const test = '/test';
+  static const home = '/home';
+  static const signIn = '/signIn';
+  static const gameLoading = '/gameLoading';
+  static const providerDetail = '/providerDetail';
+  static const needUpdate = '/needUpdate';
+  static const settlement = '/settlement';
+  static const homeSaveUserInfo = '/homeSaveUserInfo';
+
+  static const mapsList = '/mapsList'; // 地图列表
+  static const mapTO = '/mapTO'; // 地图场控
+  static const userAdmin = '/userAdmin'; // 用户管理
+  static const userRank = '/userRank'; // 个人排名
+  static const groupRank = '/groupRank'; // 分组排名
+  static const sportData = '/sportData'; // 数据详情
+  static const setting = '/setting'; // 设置
+}

+ 22 - 0
lib/service/all_init.dart

@@ -0,0 +1,22 @@
+Future<void> initBeforeApp()async{
+  // final flavor = await getFlavor();
+  // if(flavor=='dev'){
+  //   GlobalVar.apiHost='totapi-lc.beswell.com';
+  //   GlobalVar.flavor=Flavor.dev;
+  //   info('版本:dev');
+  //   FlavorConfig(
+  //     name: "开发版",
+  //     color: Colors.red,
+  //     location: BannerLocation.topStart,
+  //   );
+  // }
+}
+
+
+
+
+Future<void> allInit()async{
+
+
+
+}

+ 5 - 0
lib/service/app.dart

@@ -0,0 +1,5 @@
+import 'package:get/get.dart';
+
+class AppService extends GetxService{
+
+}

+ 71 - 0
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
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)
+  );
+}

+ 62 - 0
lib/utils.dart

@@ -0,0 +1,62 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:grpc/grpc.dart';
+export 'logger.dart';
+import 'package:common_pub/common_pub.dart';
+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;
+  }
+}
+
+
+void runPreview(Widget child){
+  runApp(GetMaterialApp(
+      theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
+      home: Preview(child: child)));
+}

+ 6 - 0
lib/view/home/home_controller.dart

@@ -0,0 +1,6 @@
+import 'package:get/get.dart';
+
+
+class HomeController extends GetxController{
+
+}

+ 20 - 0
lib/view/home/home_view.dart

@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'home_controller.dart';
+
+class HomeView extends GetView<HomeController>{
+  const HomeView({super.key});
+
+  static Bindings bindings() {
+    return BindingsBuilder(() {
+      Get.lazyPut<HomeController>(() => HomeController());
+    });
+  }
+
+
+  @override
+  Widget build(BuildContext context) {
+    return const Scaffold();
+  }
+
+}

+ 40 - 0
lib/view/init_view.dart

@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:track_offical/service/all_init.dart';
+import 'package:track_offical/view/home/home_view.dart';
+import 'package:track_offical/view/login/login_view.dart';
+
+
+class InitView extends StatefulWidget{
+  const InitView({super.key});
+
+  @override
+  State<StatefulWidget> createState() {
+    return _State();
+  }
+}
+
+class _State extends State<InitView>{
+  @override
+  Widget build(BuildContext context) {
+    return const Scaffold(body: Center());
+  }
+
+  void init()async{
+    await allInit();
+    await 1.seconds.delay();
+
+    LoginView.to(canBack: false, thenToPageCall: (){
+      Get.offAll(()=>const HomeView(), binding: HomeView.bindings());
+    });
+  }
+
+
+
+  @override
+  void initState() {
+    super.initState();
+
+    init();
+  }
+}

+ 138 - 0
lib/view/login/common.dart

@@ -0,0 +1,138 @@
+import 'package:common_pub/common_pub.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:track_offical/generated/assets.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));
+  }
+
+}

+ 124 - 0
lib/view/login/login_controller.dart

@@ -0,0 +1,124 @@
+import 'dart:async';
+import 'dart:ui';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:grpc/grpc.dart';
+import '../../utils.dart';
+
+class LoginController extends GetxController {
+  final phone = "".obs;
+  final password = "".obs;
+  final codeRetryLeft = 0.seconds.obs;
+  Timer? ticker;
+  var isSignInEnable = true;
+  final isAgreeContract = false.obs;
+
+
+  @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 ApiService.to.getSmsSendLeftTime(phone.value);
+          // if (codeRetryLeft.value.inSeconds > 0) {
+          //   return;
+          // }
+          // await ApiService.to
+          //     .authSendCodeToPhone(phone.value, pb.SmsType.Login);
+          // codeRetryLeft.value =
+          //     await ApiService.to.getSmsSendLeftTime(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;
+      }
+
+      final args = Get.arguments;
+
+      await tryApi(
+          () async {
+            info("登录 ${phone.value} ${password.value}");
+            // await ApiService.to.signIn(phone.value, password.value, '');
+            //
+            // if (Get.previousRoute == RouteName.signIn) {
+            //   Get.offAllNamed(RouteName.home);
+            // } else {
+            //   Get.back(result: true, closeOverlays: true);
+            // }
+            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 {}

+ 454 - 0
lib/view/login/login_view.dart

@@ -0,0 +1,454 @@
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:common_pub/ui/web_view.dart';
+import 'package:rive/rive.dart';
+import 'package:track_offical/generated/assets.dart';
+import '../../utils.dart';
+import 'login_controller.dart';
+import 'common.dart';
+import 'package:vector_math/vector_math.dart' as vec;
+import 'package:common_pub/common_pub.dart';
+
+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();
+  }
+
+  Widget wPageLeft() {
+    return Container(
+      decoration: const BoxDecoration(
+          image: DecorationImage(
+              image: AssetImage(Assets.imagesBkCommonPage), 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,
+                    ),
+                    SizedBox(
+                        height: context.wp(10.0),
+                        child: const RiveAnimation.asset(
+                          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.wp,
+                      //     child:
+                      //     Image.asset(Assets.imagesIcLogo, height: 5.0.wp))
+                    ],
+                  ))
+                ],
+              )),
+        ],
+      ),
+    );
+  }
+}
+
+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.wp)),
+      ],
+    );
+  }
+}
+
+class LoginView extends GetView<LoginController> {
+  const LoginView({super.key});
+
+  static Bindings bindings() {
+    return BindingsBuilder(() {
+      Get.lazyPut<LoginController>(() => LoginController());
+      // Get.put(LoginController());
+    });
+  }
+  
+  static Future<bool> to({
+    bool canBack = true,
+    VoidCallback? thenToPageCall,
+  })async{
+    
+    Future<dynamic>? r;
+    if (canBack) {
+      r = Get.to(()=>const LoginView(), binding: LoginView.bindings(),arguments: thenToPageCall);
+    } else {
+      r = Get.offAll(()=>const LoginView(), binding: LoginView.bindings(), 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) {
+    return Container(
+        margin: EdgeInsets.fromLTRB(context.wp(6), context.wp(5.6), context.wp(6), context.wp(2)),
+        padding: const EdgeInsets.all(10.0),
+        decoration: const BoxDecoration(
+          // color: Color(0xffffcb00),
+          image: DecorationImage(
+              image: AssetImage(Assets.imagesBkLoginRight),
+              alignment: Alignment.topCenter,
+              fit: BoxFit.fitWidth),
+        ),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            const Text(
+              '定向运动活动现场监控系统',
+              textAlign: TextAlign.center,
+              style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold),
+            ),
+            SizedBox(
+                height: context.height * 0.45,
+                child: wInput(context)
+            ),
+            SizedBox(
+                height: context.wp(3),
+                child: Image.asset(Assets.imagesIcLoginLogo)
+            ),
+            // 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: EdgeInsets.only(left: 41.67, right: 41.67),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Row(
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                divider(),
+                Padding(
+                    padding: EdgeInsets.only(left: 22.9, right: 22.9),
+                    child: Text(
+                      '其他登录方式',
+                      style: TextStyle(fontSize: 25.0),
+                    )),
+                divider(),
+              ],
+            ),
+            SizedBox(height: 76.5),
+            Row(),
+            const Spacer(),
+            Text.rich(TextSpan(
+                text: '还不是我们的会员?',
+                style: TextStyle(fontSize: 33.33, color: Colors.black),
+                children: [
+                  TextSpan(
+                    text: '点击注册',
+                    style: const TextStyle(color: Color(0xffffb40b)),
+                    recognizer: TapGestureRecognizer()
+                      ..onTap = () {
+                        // SignUpView.show();
+                      },
+                  ),
+                ])),
+            SizedBox(height: 76.5),
+          ],
+        ));
+  }
+
+  Widget divider() {
+    return Expanded(
+        child: Container(
+      height: 2.0,
+      color: Colors.black,
+    ));
+  }
+}
+
+class _TextContract extends GetView<LoginController> {
+  @override
+  Widget build(BuildContext context) {
+    const color = Color(0xffffb40b);
+
+    return Row(
+      children: [
+        Obx(() => Checkbox(
+              value: controller.isAgreeContract.value,
+              onChanged: (v) => controller.isAgreeContract.value = (v ?? false),
+            )),
+        Expanded(
+            child: Text.rich(TextSpan(
+                text: '我已阅读并同意',
+                style: const TextStyle(fontSize: 11, color: Color(0xFF999999)),
+                children: [
+              TextSpan(
+                text: '《用户协议》',
+                style: const TextStyle(color: color),
+                recognizer: TapGestureRecognizer()
+                  ..onTap = () {
+                    Get.to(() => WebView(
+                        url: 'https://www.beswell.com/ot_agreement.html'));
+                  },
+              ),
+              const TextSpan(text: '和'),
+              TextSpan(
+                text: '《隐私政策》',
+                style: const TextStyle(color: color),
+                recognizer: TapGestureRecognizer()
+                  ..onTap = () {
+                    Get.to(() =>
+                        WebView(url: 'https://beswell.com/privacy-ot.html'));
+                  },
+              ),
+            ])))
+      ],
+    );
+  }
+}
+
+void main() {
+  Get.put(LoginController());
+  runPreview(const LoginView());
+}

+ 109 - 0
lib/view/login/logo_widget.dart

@@ -0,0 +1,109 @@
+import 'package:flutter/material.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/images/sign_in_logo.png', 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
macos/Flutter/GeneratedPluginRegistrant.swift

@@ -6,7 +6,13 @@ import FlutterMacOS
 import Foundation
 
 import common_pub
+import package_info_plus
+import rive_common
+import wakelock_plus
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   CommonPubPlugin.register(with: registry.registrar(forPlugin: "CommonPubPlugin"))
+  FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
+  RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin"))
+  WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
 }

+ 181 - 5
pubspec.lock

@@ -96,6 +96,14 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.5"
+  dbus:
+    dependency: transitive
+    description:
+      name: dbus
+      sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.7.8"
   fake_async:
     dependency: transitive
     description:
@@ -112,11 +120,27 @@ packages:
       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"
   flutter:
     dependency: "direct main"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_flavor:
+    dependency: "direct main"
+    description:
+      name: flutter_flavor
+      sha256: "187c614e0351beada25a30420e80ffc06ddc73f7b7d5669447346757e1e26b56"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.3"
   flutter_lints:
     dependency: "direct dev"
     description:
@@ -143,6 +167,38 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  get:
+    dependency: "direct main"
+    description:
+      name: get
+      sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.6.5"
+  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: "220ffb2218288f4e7dea487242e08b9c6277596d9b6f3f10ba50be96771a032d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.2.3"
   http:
     dependency: transitive
     description:
@@ -151,6 +207,14 @@ packages:
       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:
@@ -175,6 +239,14 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.1"
+  logger:
+    dependency: "direct main"
+    description:
+      name: logger
+      sha256: "66cb048220ca51cf9011da69fa581e4ee2bed4be6e82870d9e9baae75739da49"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.1"
   logging:
     dependency: transitive
     description:
@@ -215,6 +287,22 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.4"
+  package_info_plus:
+    dependency: transitive
+    description:
+      name: package_info_plus
+      sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.1.0"
+  package_info_plus_platform_interface:
+    dependency: transitive
+    description:
+      name: package_info_plus_platform_interface
+      sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.1"
   path:
     dependency: transitive
     description:
@@ -227,10 +315,10 @@ packages:
     dependency: transitive
     description:
       name: petitparser
-      sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6
+      sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "6.0.1"
+    version: "5.4.0"
   plugin_platform_interface:
     dependency: transitive
     description:
@@ -255,14 +343,38 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.5.1"
+  protobuf:
+    dependency: "direct main"
+    description:
+      name: protobuf
+      sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.0"
   puppeteer:
     dependency: transitive
     description:
       name: puppeteer
-      sha256: "0d27d2923d17fccb9792538452da63f242ac0ee31d46bc73df622c029c7ee86f"
+      sha256: "59e723cc5b69537159a7c34efd645dc08a6a1ac4647d7d7823606802c0f93cdb"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.2.0"
+  rive:
+    dependency: "direct main"
+    description:
+      name: rive
+      sha256: b7780ebdc56320da1f02a39a18f050a6079cad60c0cb92003c0801cc4eec6673
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.11.14"
+  rive_common:
+    dependency: transitive
+    description:
+      name: rive_common
+      sha256: "1431b99c9f361234cc6fa9aee7987b20030622df25ff64343a4010f9446b275e"
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "3.3.0"
+    version: "0.2.6"
   shelf:
     dependency: transitive
     description:
@@ -372,6 +484,22 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.1.4"
+  wakelock_plus:
+    dependency: "direct main"
+    description:
+      name: wakelock_plus
+      sha256: aac3f3258f01781ec9212df94eecef1eb9ba9350e106728def405baa096ba413
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.1"
+  wakelock_plus_platform_interface:
+    dependency: transitive
+    description:
+      name: wakelock_plus_platform_interface
+      sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
   web:
     dependency: transitive
     description:
@@ -388,6 +516,54 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "2.4.0"
+  webview_flutter:
+    dependency: transitive
+    description:
+      name: webview_flutter
+      sha256: "04a0782fb058b7c71f2048935583488f4d32e9147ca403abc4e58f1de9964629"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.2.3"
+  webview_flutter_android:
+    dependency: transitive
+    description:
+      name: webview_flutter_android
+      sha256: bca797abba472868655b5f1a6029c1132385685ee9db4713cb0e7f33076210c6
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.9.3"
+  webview_flutter_platform_interface:
+    dependency: transitive
+    description:
+      name: webview_flutter_platform_interface
+      sha256: "0ca3cfcc6781a7de701d580917af4a9efc4e3e129f8ead95a80587f0a749480a"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.5.0"
+  webview_flutter_wkwebview:
+    dependency: transitive
+    description:
+      name: webview_flutter_wkwebview
+      sha256: ed749f94ac9e814d04a258a9255cf69cfa4cc6006ff59542aea7fb4590144972
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.7.3"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "5.0.7"
+  xml:
+    dependency: transitive
+    description:
+      name: xml
+      sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.3.0"
   yaml:
     dependency: transitive
     description:
@@ -398,4 +574,4 @@ packages:
     version: "3.1.2"
 sdks:
   dart: ">=3.1.0 <4.0.0"
-  flutter: ">=3.3.0"
+  flutter: ">=3.7.0"

+ 11 - 0
pubspec.yaml

@@ -36,6 +36,14 @@ dependencies:
   cupertino_icons: ^1.0.2
   common_pub:
     path: third_party/common_pub
+  get: ^4.6.5
+  logger: ^2.0.1
+  grpc: ^3.2.3
+  protobuf: ^3.1.0
+  wakelock_plus: ^1.1.1
+  flutter_flavor: ^3.1.3
+  rive: ^0.11.14
+
 
 dev_dependencies:
   flutter_test:
@@ -89,3 +97,6 @@ flutter:
   #
   # For details regarding fonts from package dependencies,
   # see https://flutter.dev/custom-fonts/#from-packages
+  assets:
+    - assets/images/
+

+ 13 - 13
test/widget_test.dart

@@ -13,18 +13,18 @@ import 'package:track_offical/main.dart';
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {
     // Build our app and trigger a frame.
-    await tester.pumpWidget(const MyApp());
-
-    // Verify that our counter starts at 0.
-    expect(find.text('0'), findsOneWidget);
-    expect(find.text('1'), findsNothing);
-
-    // Tap the '+' icon and trigger a frame.
-    await tester.tap(find.byIcon(Icons.add));
-    await tester.pump();
-
-    // Verify that our counter has incremented.
-    expect(find.text('0'), findsNothing);
-    expect(find.text('1'), findsOneWidget);
+    // await tester.pumpWidget(const MyApp());
+    //
+    // // Verify that our counter starts at 0.
+    // expect(find.text('0'), findsOneWidget);
+    // expect(find.text('1'), findsNothing);
+    //
+    // // Tap the '+' icon and trigger a frame.
+    // await tester.tap(find.byIcon(Icons.add));
+    // await tester.pump();
+    //
+    // // Verify that our counter has incremented.
+    // expect(find.text('0'), findsNothing);
+    // expect(find.text('1'), findsOneWidget);
   });
 }

+ 1 - 1
third_party/common_pub

@@ -1 +1 @@
-Subproject commit a68161f055de30ed5f6cdc2afc7e35c611c01f8e
+Subproject commit 88da4a9bfad945a5c4e9b03b28231de6d152c661

+ 3 - 0
windows/flutter/generated_plugin_registrant.cc

@@ -7,8 +7,11 @@
 #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"));
 }

+ 1 - 0
windows/flutter/generated_plugins.cmake

@@ -4,6 +4,7 @@
 
 list(APPEND FLUTTER_PLUGIN_LIST
   common_pub
+  rive_common
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST