Browse Source

地图列表

周睿 2 years ago
parent
commit
5d9f303806

BIN
assets/images/ic_no_data.png


+ 1 - 0
lib/generated/assets.dart

@@ -9,6 +9,7 @@ class Assets {
   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';
 
 }

+ 0 - 1
lib/global_var.dart

@@ -1,4 +1,3 @@
-import 'package:flutter/foundation.dart';
 
 enum Flavor{ dev, prod }
 

+ 3 - 2
lib/main.dart

@@ -1,6 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:track_offical/view/init_view.dart';
+import 'logger.dart';
+import 'view/init_view.dart';
 import 'styles/theme.dart';
 
 
@@ -14,7 +15,7 @@ class App extends StatelessWidget{
 
   @override
   Widget build(BuildContext context) {
-
+    info('size: ${MediaQuery.of(context).size}');
     return GetMaterialApp(
       debugShowCheckedModeBanner: true,
       title: '小飞龙定向场控',

+ 3 - 0
lib/model/game_map.dart

@@ -0,0 +1,3 @@
+class GameMap {
+
+}

+ 0 - 3
lib/route.dart

@@ -1,6 +1,3 @@
-import 'package:flutter/foundation.dart';
-import 'package:get/get.dart';
-
 class RouteName {
   static const init = '/init';
   static const test = '/test';

+ 61 - 0
lib/utils.dart

@@ -1,3 +1,7 @@
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:f_cache/manager.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:grpc/grpc.dart';
@@ -5,6 +9,8 @@ export 'logger.dart';
 import 'package:common_pub/common_pub.dart';
 import 'styles/color_schemes.g.dart';
 import 'view/login/login_view.dart';
+import 'pb.dart' as pb;
+import 'package:http/http.dart' as http;
 
 
 Future<void> tryApi(Future<void> Function() call, {
@@ -54,6 +60,61 @@ class Preview extends StatelessWidget{
   }
 }
 
+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);
+  }
+
+}
+
+
+extension Uint8ListExtension on Uint8List {
+  String toHexString({String separator = ''}) {
+    return isEmpty
+        ? ""
+        : map((e) {
+      var s = e.toRadixString(16).toUpperCase();
+      if (e < 10) {
+        s = '0$s';
+      }
+      return s;
+    }).join(separator);
+  }
+}
+extension IntListExtension on List<int> {
+  String toHexString({String separator = ''}) {
+    return isEmpty
+        ? ""
+        : map((e) {
+      var s = e.toRadixString(16).toUpperCase();
+      if (e < 10) {
+        s = '0$s';
+      }
+      return s;
+    }).join(separator);
+  }
+}
+
 
 void runPreview(Widget child){
   runApp(GetMaterialApp(

+ 1 - 1
lib/view/home/app_bar.dart

@@ -1,7 +1,7 @@
 import 'package:common_pub/common_pub.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:track_offical/generated/assets.dart';
+import '../../generated/assets.dart';
 import 'home_controller.dart';
 
 class HomeAppBar extends GetView<HomeController> implements PreferredSizeWidget{

+ 42 - 0
lib/view/home/data_detail/data_detail.dart

@@ -0,0 +1,42 @@
+import 'package:application/widget.dart';
+import 'package:application/model/game_map.dart';
+import 'data_detail_controller.dart';
+
+
+class DataDetailPage extends StatelessWidget{
+  const DataDetailPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return GetBuilder(
+        init: DataDetailController(),
+        builder: (c){
+          return Container(
+            height: double.infinity,
+            width: double.infinity,
+            color: const Color(0xffc9c0c0),
+            alignment: Alignment.center,
+            child: Obx(() => c.gameMap != null? content(context, c.gameMap!): noData(),
+          ));
+    });
+  }
+
+
+  Widget noData(){
+    return Center(
+      child: Column(
+        mainAxisSize: MainAxisSize.min,
+        children: [
+          Image.asset(Assets.imagesIcNoData, height: 64),
+          const SizedBox(height: 25),
+          const Text('没有数据, 请选择地图',
+              style: TextStyle(color: Color(0xff707070), fontSize: 18.5)),
+        ],
+      ),
+    );
+  }
+
+  Widget content(BuildContext context, GameMap gameMap){
+    return Container();
+  }
+}

+ 9 - 0
lib/view/home/data_detail/data_detail_controller.dart

@@ -0,0 +1,9 @@
+import 'package:get/get.dart';
+import '../home_controller.dart';
+
+class DataDetailController extends GetxController{
+  HomeController get _home => Get.find();
+
+  GameMap? get gameMap => _home.gameMap.value;
+
+}

+ 3 - 2
lib/view/home/home_controller.dart

@@ -1,6 +1,7 @@
 import 'package:get/get.dart';
-
+import '../../model/game_map.dart';
+export '../../model/game_map.dart';
 
 class HomeController extends GetxController{
-
+  final Rx<GameMap?> gameMap = Rx(null);
 }

+ 3 - 6
lib/view/home/home_view.dart

@@ -1,11 +1,8 @@
-import 'package:common_pub/common_pub.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import '../../generated/assets.dart';
-import '../../logger.dart';
+import 'data_detail/data_detail.dart';
 import 'app_bar.dart';
 import 'map/map_page.dart';
 import 'home_controller.dart';
+import 'package:application/widget.dart';
 
 class HomeView extends GetView<HomeController> {
   const HomeView({super.key});
@@ -51,7 +48,7 @@ final _tabElems = [
   _TabElem(title: '用户管理', child: const SizedBox()),
   _TabElem(title: '个人排名', child: const SizedBox()),
   _TabElem(title: '分组排名', child: const SizedBox()),
-  _TabElem(title: '数据详情', child: const SizedBox()),
+  _TabElem(title: '数据详情', child: const DataDetailPage()),
 ];
 
 class _TabElem {

+ 12 - 20
lib/view/home/map/map_page.dart

@@ -1,10 +1,11 @@
 import 'package:common_pub/model/distance.dart';
 import 'package:flutter/material.dart';
 import 'package:get/get.dart';
-import 'package:track_offical/service/api.dart' as api;
-import 'package:track_offical/utils.dart';
+import '../../../service/api.dart' as api;
+import '../../../utils.dart';
 import 'package:common_pub/model/position.dart' as m;
 import '../../../generated/assets.dart';
+import '../../../widget/app_net_image.dart';
 
 typedef MapInfo = api.ToMapSimpleV2;
 
@@ -87,7 +88,7 @@ class MapPage extends StatelessWidget {
                                 crossAxisSpacing: 10,
                                 //设置主轴间距
                                 mainAxisSpacing: 10,
-                                childAspectRatio: 0.66),
+                                childAspectRatio: 1.3),
                         itemBuilder: (context, i) {
                           return GalleryCardWidget(data: c.mapList[i], position: c.position.value);
                         })))
@@ -126,10 +127,11 @@ class GalleryCardWidget extends StatelessWidget {
         shape: const RoundedRectangleBorder(
             borderRadius: BorderRadius.all(Radius.circular(5.44))),
         clipBehavior: Clip.antiAlias,
+        elevation: 2,
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
-            AspectRatio(aspectRatio: 1, child: wImage()),
+            AspectRatio(aspectRatio: 1.1, child: AppNetImage(netImage: data.image, fit: BoxFit.fitHeight)),
             Expanded(
                 child: Padding(
                     padding: const EdgeInsets.all(6),
@@ -140,7 +142,7 @@ class GalleryCardWidget extends StatelessWidget {
                         Text(
                           data.name,
                           style: const TextStyle(
-                            fontSize: 15.24,
+                            fontSize: 13.5,
                             fontWeight: FontWeight.w500,
                           ),
                           textAlign: TextAlign.start,
@@ -150,7 +152,7 @@ class GalleryCardWidget extends StatelessWidget {
                         Text(
                           data.description,
                           style: const TextStyle(
-                            fontSize: 19,
+                            fontSize: 10,
                             color: Color(0xffc6c6c6),
                           ),
                           textAlign: TextAlign.start,
@@ -160,17 +162,17 @@ class GalleryCardWidget extends StatelessWidget {
                         const Spacer(),
                         DefaultTextStyle(
                             style: const TextStyle(
-                                color: Colors.black, fontSize: 14),
+                                color: Colors.black, fontSize: 10),
                             child: Row(
                               crossAxisAlignment: CrossAxisAlignment.end,
                               mainAxisAlignment: MainAxisAlignment.spaceBetween,
                               children: [
                                 Image.asset(Assets.imagesIcMapScale,
-                                    height: 14),
+                                    height: 9.6),
                                 Text(' 1:${data.mapScaleNumber}'),
                                 const Spacer(),
                                 Image.asset(Assets.imagesIcLocation,
-                                    height: 14),
+                                    height:  9.6),
                                 Text(' $distance'),
                               ],
                             ))
@@ -187,18 +189,8 @@ class GalleryCardWidget extends StatelessWidget {
       children: [
         SizedBox(
             height: double.infinity,
-            // child: AppNetImage(netImage: data.image, fit: BoxFit.fitHeight)
+            child: AppNetImage(netImage: data.image, fit: BoxFit.fitHeight)
         ),
-        Container(
-                width: double.infinity,
-                height: double.infinity,
-                color: Colors.white.withAlpha(178),
-                alignment: Alignment.center,
-                child: const Text(
-                  '待开放',
-                  style: TextStyle(color: Color(0xffff6203), fontSize: 15.24),
-                ),
-              )
       ],
     );
   }

+ 1 - 3
lib/view/login/common.dart

@@ -1,7 +1,5 @@
 import 'package:common_pub/common_pub.dart';
-import 'package:flutter/material.dart';
-import 'package:get/get.dart';
-import 'package:track_offical/generated/assets.dart';
+import '../../widget.dart';
 
 class AppTopBar extends StatelessWidget implements PreferredSizeWidget {
   const AppTopBar(

+ 7 - 10
lib/view/login/login_view.dart

@@ -1,13 +1,10 @@
 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 'package:application/widget.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;
@@ -360,7 +357,7 @@ class LoginView extends GetView<LoginController> {
 
   Widget wExtra() {
     return Padding(
-        padding: EdgeInsets.only(left: 41.67, right: 41.67),
+        padding: const EdgeInsets.only(left: 41.67, right: 41.67),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.center,
           children: [
@@ -368,7 +365,7 @@ class LoginView extends GetView<LoginController> {
               crossAxisAlignment: CrossAxisAlignment.center,
               children: [
                 divider(),
-                Padding(
+                const Padding(
                     padding: EdgeInsets.only(left: 22.9, right: 22.9),
                     child: Text(
                       '其他登录方式',
@@ -377,12 +374,12 @@ class LoginView extends GetView<LoginController> {
                 divider(),
               ],
             ),
-            SizedBox(height: 76.5),
-            Row(),
+            const SizedBox(height: 76.5),
+            const Row(),
             const Spacer(),
             Text.rich(TextSpan(
                 text: '还不是我们的会员?',
-                style: TextStyle(fontSize: 33.33, color: Colors.black),
+                style: const TextStyle(fontSize: 33.33, color: Colors.black),
                 children: [
                   TextSpan(
                     text: '点击注册',
@@ -393,7 +390,7 @@ class LoginView extends GetView<LoginController> {
                       },
                   ),
                 ])),
-            SizedBox(height: 76.5),
+            const SizedBox(height: 76.5),
           ],
         ));
   }

+ 4 - 0
lib/widget.dart

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

+ 99 - 0
lib/widget/app_net_image.dart

@@ -0,0 +1,99 @@
+import 'package:f_cache/f_cache.dart';
+import 'prelude.dart';
+import '../utils.dart';
+
+
+class AppNetImage extends StatefulWidget{
+  const AppNetImage({
+    super.key,
+    required this.netImage,
+    this.fit,
+    this.onWidgetOk, this.width, this.height
+  });
+
+  final NetImage netImage;
+  final BoxFit? fit;
+  final VoidCallback? onWidgetOk;
+  final double? width;
+  final double? height;
+
+  @override
+  State<StatefulWidget> createState() {
+    return _AppNetImageState();
+  }
+}
+CachedReaderImage cachedProvider(NetImage image){
+  return CachedReaderImage(image.md5Hex ?? '', image.readerBuilder);
+}
+class _AppNetImageState extends State<AppNetImage>{
+
+  late CachedReaderImage provider;
+
+  @override
+  void initState() {
+    super.initState();
+    final image = widget.netImage;
+    provider =  cachedProvider(image);
+  }
+
+
+  @override
+  void didUpdateWidget(covariant AppNetImage oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    final image = widget.netImage;
+    provider =  cachedProvider(image);
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Image(
+      image: provider,
+      loadingBuilder: (
+          BuildContext context,
+          Widget child,
+          ImageChunkEvent? loadingProgress){
+
+        if(loadingProgress!= null){
+          var p = 0.0;
+          final all = loadingProgress.expectedTotalBytes?? 0;
+          if(all > 0){
+            p = loadingProgress.cumulativeBytesLoaded.toDouble() / all.toDouble();
+          }
+          return ImageLoading(value: p);
+        }else{
+          return child;
+        }
+      },
+      errorBuilder: (ctx, e, trace){
+        warn('图片加载失败: ${widget.netImage.url}  md5: ${widget.netImage.md5Hex}', e);
+        return Container(color: Colors.white, child:const Center(child: Icon(Icons.broken_image_outlined)));
+      },
+      width: widget.width,
+      height: widget.height,
+      fit: widget.fit,
+    );
+  }
+}
+
+class ImageLoading extends StatelessWidget{
+  final double? value;
+  const ImageLoading({
+    super.key,
+    this.value
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      decoration: BoxDecoration(color: Colors.grey.withAlpha(20)),
+      child:Center(
+        child: SizedBox(
+            width: 48, height: 48,
+            child: CircularProgressIndicator(
+                value: value
+            )),
+      )  ,
+    );
+  }
+
+}

+ 3 - 0
lib/widget/prelude.dart

@@ -0,0 +1,3 @@
+export 'package:flutter/material.dart';
+export '../generated/assets.dart';
+export 'package:get/get.dart';

+ 11 - 3
pubspec.lock

@@ -104,6 +104,14 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.7.8"
+  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:
@@ -208,7 +216,7 @@ packages:
     source: hosted
     version: "3.2.3"
   http:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: http
       sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
@@ -427,10 +435,10 @@ packages:
     dependency: "direct main"
     description:
       name: rive
-      sha256: b7780ebdc56320da1f02a39a18f050a6079cad60c0cb92003c0801cc4eec6673
+      sha256: "0ed73d33bb501da49001510e456789c279ffa017370748bcde846693645640e0"
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.11.14"
+    version: "0.11.15"
   rive_common:
     dependency: transitive
     description:

+ 4 - 2
pubspec.yaml

@@ -1,4 +1,4 @@
-name: track_offical
+name: application
 description: A new Flutter project.
 # The following line prevents the package from being accidentally published to
 # pub.dev using `flutter pub publish`. This is preferred for private packages.
@@ -42,10 +42,12 @@ dependencies:
   protobuf: ^3.1.0
   wakelock_plus: ^1.1.1
   flutter_flavor: ^3.1.3
-  rive: ^0.11.14
+  rive: ^0.11.15
   get_storage: ^2.1.1
   package_info_plus: ^4.1.0
   system_clock: ^2.0.0
+  f_cache: ^3.1.1
+  http: ^1.1.0
 
 
 dev_dependencies:

+ 0 - 2
test/widget_test.dart

@@ -5,10 +5,8 @@
 // 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/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 
-import 'package:track_offical/main.dart';
 
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {