周睿 2 yıl önce
ebeveyn
işleme
a6e2a1624e

+ 14 - 0
lib/generated/base.pb.dart

@@ -228,6 +228,7 @@ class HeartRate extends $pb.GeneratedMessage {
   factory HeartRate({
     $fixnum.Int64? timeStampMs,
     $core.int? hr,
+    $core.int? hrPer,
   }) {
     final $result = create();
     if (timeStampMs != null) {
@@ -236,6 +237,9 @@ class HeartRate extends $pb.GeneratedMessage {
     if (hr != null) {
       $result.hr = hr;
     }
+    if (hrPer != null) {
+      $result.hrPer = hrPer;
+    }
     return $result;
   }
   HeartRate._() : super();
@@ -245,6 +249,7 @@ class HeartRate extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'HeartRate', package: const $pb.PackageName(_omitMessageNames ? '' : 'base.v1'), createEmptyInstance: create)
     ..aInt64(1, _omitFieldNames ? '' : 'timeStampMs', protoName: 'timeStampMs')
     ..a<$core.int>(2, _omitFieldNames ? '' : 'hr', $pb.PbFieldType.O3)
+    ..a<$core.int>(3, _omitFieldNames ? '' : 'hrPer', $pb.PbFieldType.O3, protoName: 'hrPer')
     ..hasRequiredFields = false
   ;
 
@@ -286,6 +291,15 @@ class HeartRate extends $pb.GeneratedMessage {
   $core.bool hasHr() => $_has(1);
   @$pb.TagNumber(2)
   void clearHr() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.int get hrPer => $_getIZ(2);
+  @$pb.TagNumber(3)
+  set hrPer($core.int v) { $_setSignedInt32(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasHrPer() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearHrPer() => clearField(3);
 }
 
 class SignInReply extends $pb.GeneratedMessage {

+ 2 - 1
lib/generated/base.pbjson.dart

@@ -284,13 +284,14 @@ const HeartRate$json = {
   '2': [
     {'1': 'timeStampMs', '3': 1, '4': 1, '5': 3, '10': 'timeStampMs'},
     {'1': 'hr', '3': 2, '4': 1, '5': 5, '10': 'hr'},
+    {'1': 'hrPer', '3': 3, '4': 1, '5': 5, '10': 'hrPer'},
   ],
 };
 
 /// Descriptor for `HeartRate`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List heartRateDescriptor = $convert.base64Decode(
     'CglIZWFydFJhdGUSIAoLdGltZVN0YW1wTXMYASABKANSC3RpbWVTdGFtcE1zEg4KAmhyGAIgAS'
-    'gFUgJocg==');
+    'gFUgJochIUCgVoclBlchgDIAEoBVIFaHJQZXI=');
 
 @$core.Deprecated('Use signInReplyDescriptor instead')
 const SignInReply$json = {

+ 1 - 1
lib/styles/theme.dart

@@ -6,6 +6,6 @@ ThemeData appThemeData(){
   return ThemeData(
       useMaterial3: true,
       colorScheme: lightColorScheme,
-      scaffoldBackgroundColor: const Color(0xffF0F0F0)
+      scaffoldBackgroundColor: const Color(0xffF0F0F0),
   );
 }

+ 106 - 84
lib/view/home/field_control/field_control.dart

@@ -7,29 +7,29 @@ import 'package:common_pub/ui/map_view/view_plug_loading.dart';
 import 'package:common_pub/utils.dart';
 import 'field_control_controller.dart';
 
-
-class FieldControlPage extends StatelessWidget{
+class FieldControlPage extends StatelessWidget {
   const FieldControlPage({super.key});
 
   @override
   Widget build(BuildContext context) {
     return GetBuilder(
         init: FieldControlController(),
-        builder: (c){
+        builder: (c) {
           return Container(
-            height: double.infinity,
-            width: double.infinity,
-            color: const Color(0xffc9c0c0),
-            alignment: Alignment.center,
-            child: Obx((){
-              final mapWatch = c.mapWatch;
-              return mapWatch != null? content(context, mapWatch, c): noData();
-            }));
-    });
+              height: double.infinity,
+              width: double.infinity,
+              color: const Color(0xffc9c0c0),
+              alignment: Alignment.center,
+              child: Obx(() {
+                final mapWatch = c.mapWatch;
+                return mapWatch != null
+                    ? content(context, mapWatch, c)
+                    : noData();
+              }));
+        });
   }
 
-
-  Widget noData(){
+  Widget noData() {
     return Center(
       child: Column(
         mainAxisSize: MainAxisSize.min,
@@ -43,12 +43,15 @@ class FieldControlPage extends StatelessWidget{
     );
   }
 
-  Widget content(BuildContext context, MapWatchService map, FieldControlController c){
+  Widget content(
+      BuildContext context, MapWatchService map, FieldControlController c) {
     return Row(
       children: [
-        Expanded(child: Column(
+        Expanded(
+            child: Column(
           children: [
-            Expanded(child: ViewMapStack(plug: map.plugMap, children: [
+            Expanded(
+                child: ViewMapStack(plug: map.plugMap, children: [
               ViewPlugLoading(map.plugMap),
               ViewMapImage(map.plugMap),
               _ViewTrace(map: map),
@@ -62,65 +65,70 @@ class FieldControlPage extends StatelessWidget{
     );
   }
 }
-class _ViewTrace extends GetView<FieldControlController>{
+
+class _ViewTrace extends GetView<FieldControlController> {
   const _ViewTrace({required this.map});
+
   final MapWatchService map;
 
   @override
   Widget build(BuildContext context) {
-    return Obx((){
+    return Obx(() {
       final children = <Widget>[];
 
-      for(final act in map.activeList){
-        for(final user in act.userList){
-          if(user.isHide.value){
+      for (final act in map.activeList) {
+        for (final user in act.userList) {
+          if (user.isHide.value) {
             continue;
           }
           final trace = user.trace.lastOrNull;
-          if(trace != null){
-            children.add(ViewMapUserPoint(map.plugMap, trace, info: user.name, color: user.flag.value.color));
+          if (trace != null) {
+            children.add(ViewMapUserPoint(map.plugMap, trace,
+                info: user.name, color: user.flag.value.color));
           }
         }
       }
 
-      return Stack(
-        alignment: Alignment.topLeft,
-          children: children
-      );
+      return Stack(alignment: Alignment.topLeft, children: children);
     });
   }
-
 }
-class _ActiveInfoView extends GetView<FieldControlController>{
 
+class _ActiveInfoView extends GetView<FieldControlController> {
   @override
   Widget build(BuildContext context) {
     return Obx(() => Container(
-      width: 370,
-      height: double.infinity,
-      color: Colors.white,
-      child: ListView(
-        children: controller.activeList.map((element) => activeView(element)).toList(),
-      ),
-    )) ;
+          width: 370,
+          height: double.infinity,
+          color: Colors.white,
+          child: ListView(
+            children: controller.activeList
+                .map((element) => activeView(element))
+                .toList(),
+          ),
+        ));
   }
 
-  Widget activeView(ActiveInfo info){
+  Widget activeView(ActiveInfo info) {
     final children = <Widget>[
       Row(children: [
         Text('${info.name} (${info.userList.length}人)'),
         const Spacer(),
-        IconButton(onPressed: (){
-          info.isHide.value=!info.isHide.value;
-        }, icon: info.isHide.value?const Icon(Icons.arrow_drop_down):const Icon(Icons.arrow_drop_up))
+        IconButton(
+            onPressed: () {
+              info.isHide.value = !info.isHide.value;
+            },
+            icon: info.isHide.value
+                ? const Icon(Icons.arrow_drop_down)
+                : const Icon(Icons.arrow_drop_up))
       ]),
-
     ];
 
-    if(!info.isHide.value){
+    if (!info.isHide.value) {
       children.addAll([
         Container(
-          decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(5)),
+          decoration: BoxDecoration(
+              color: Colors.white, borderRadius: BorderRadius.circular(5)),
           padding: const EdgeInsets.fromLTRB(26, 11, 26, 11),
           child: Row(
             children: [
@@ -134,15 +142,14 @@ class _ActiveInfoView extends GetView<FieldControlController>{
           ),
         )
       ]);
-      children.addAll(info.userList.map((e) => _UserInfoView(data: e)).toList());
+      children
+          .addAll(info.userList.map((e) => _UserInfoView(data: e)).toList());
     }
 
-
-
-
-
     return Container(
-      decoration: BoxDecoration(color: const Color(0xffe0e0e0), borderRadius: BorderRadius.circular(5)),
+      decoration: BoxDecoration(
+          color: const Color(0xffe0e0e0),
+          borderRadius: BorderRadius.circular(5)),
       margin: const EdgeInsets.fromLTRB(9, 12, 9, 12),
       padding: const EdgeInsets.all(9),
       child: Column(
@@ -152,7 +159,7 @@ class _ActiveInfoView extends GetView<FieldControlController>{
   }
 }
 
-class _UserInfoView extends GetView<FieldControlController>{
+class _UserInfoView extends GetView<FieldControlController> {
   const _UserInfoView({required this.data});
 
   final UserInfo data;
@@ -160,7 +167,8 @@ class _UserInfoView extends GetView<FieldControlController>{
   @override
   Widget build(BuildContext context) {
     return Container(
-      decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(5)),
+      decoration: BoxDecoration(
+          color: Colors.white, borderRadius: BorderRadius.circular(5)),
       padding: const EdgeInsets.fromLTRB(7, 11, 7, 11),
       margin: const EdgeInsets.only(top: 5),
       child: Row(
@@ -168,21 +176,35 @@ class _UserInfoView extends GetView<FieldControlController>{
         children: [
           Obx(() => Container(
               margin: const EdgeInsets.only(top: 2),
-              decoration: BoxDecoration(color: data.flag.value.color, borderRadius: BorderRadius.circular(4)),
-              width: 7, height: 16)),
-          const SizedBox(width: 8,),
-          Expanded(child: Column(
+              decoration: BoxDecoration(
+                  color: data.flag.value.color,
+                  borderRadius: BorderRadius.circular(4)),
+              width: 7,
+              height: 16)),
+          const SizedBox(
+            width: 8,
+          ),
+          Expanded(
+              child: Column(
             crossAxisAlignment: CrossAxisAlignment.start,
             children: [
-              Text.rich(TextSpan(text: data.name,  children: [
-                TextSpan(text: ' [${data.routeName}]')
-              ])),
+              Text.rich(TextSpan(
+                  text: data.name,
+                  children: [TextSpan(text: ' [${data.routeName}]')])),
               const SizedBox(height: 5),
               Row(
                 children: [
                   container(null, cpInfo, Colors.blue),
-                  container(const Icon(Icons.favorite, size: 13, color: Colors.white,), ' ${hr==0?'--':hr}', 0.toHRPColor()),
-                  container(null, paceInfo, Colors.blue)
+                  container(
+                      const Icon(
+                        Icons.favorite,
+                        size: 13,
+                        color: Colors.white,
+                      ),
+                      ' ${hr == 0 ? '--' : hr}',
+                      (data.gameInfo.hrInfo.hrInfo.lastOrNull?.hrPer ?? 0)
+                          .toHRPColor()),
+                  container(null, paceInfo, data.pace.color)
                 ],
               ),
               const SizedBox(height: 5),
@@ -197,59 +219,59 @@ class _UserInfoView extends GetView<FieldControlController>{
             ],
           )),
           GestureDetector(
-            onTap: (){
-              data.isHide.value=!data.isHide.value;
+            onTap: () {
+              data.isHide.value = !data.isHide.value;
             },
-            child: Obx(()=> Icon(
-              data.isHide.value?
-              Icons.visibility_off
-                  :Icons.visibility,
-              color: data.isHide.value? Colors.grey: const Color(0xffffbb77),)) ,
+            child: Obx(() => Icon(
+                  data.isHide.value ? Icons.visibility_off : Icons.visibility,
+                  color:
+                      data.isHide.value ? Colors.grey : const Color(0xffffbb77),
+                )),
           )
         ],
       ),
     );
   }
-  int get hr{
-    return data.gameInfo.hrInfo.hrInfo.lastOrNull?.hr??0;
+
+  int get hr {
+    return data.gameInfo.hrInfo.hrInfo.lastOrNull?.hr ?? 0;
   }
 
-  String get cpInfo{
+  String get cpInfo {
     final next = data.nextWant;
     return '${data.gameInfo.gameSaveInfo.nextControlPoint.orderNo}号点(${next?.sn})';
   }
-  String get paceInfo{
+
+  String get paceInfo {
     Duration;
     return data.pace.toString();
   }
 
-  Widget container(Widget? icon, String text, Color color){
+  Widget container(Widget? icon, String text, Color color) {
     final children = <Widget>[];
-    if(icon!= null){
+    if (icon != null) {
       children.add(icon);
     }
-    children.add(Text(text, style: const TextStyle(color: Colors.white, fontSize: 14)));
+    children.add(
+        Text(text, style: const TextStyle(color: Colors.white, fontSize: 14)));
 
     return Container(
       height: 18,
-      padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
-      margin: const EdgeInsets.only(right: 10),
+      padding: const EdgeInsets.fromLTRB(10, 0, 12, 0),
+      margin: const EdgeInsets.only(right: 6),
       alignment: Alignment.center,
-      decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(9)),
+      decoration:
+          BoxDecoration(color: color, borderRadius: BorderRadius.circular(9)),
       child: Row(
         children: children,
       ),
     );
   }
-
 }
 
-
-class _MsgView extends GetView<FieldControlController>{
-
+class _MsgView extends GetView<FieldControlController> {
   @override
   Widget build(BuildContext context) {
     return Container();
   }
-
-}
+}

+ 2 - 1
lib/view/home/home_view.dart

@@ -1,3 +1,4 @@
+import 'personal_rank/personal_rank.dart';
 import 'field_control/field_control.dart';
 import 'user_manage/user_manage_page.dart';
 import 'data_detail/data_detail.dart';
@@ -49,7 +50,7 @@ final _tabElems = [
   _TabElem(title: '地图', child: const MapPage()),
   _TabElem(title: '场控', child: const FieldControlPage()),
   _TabElem(title: '用户管理', child: const UserManagePage()),
-  _TabElem(title: '个人排名', child: const SizedBox()),
+  _TabElem(title: '个人排名', child: const PersonalRankPage()),
   _TabElem(title: '分组排名', child: const SizedBox()),
   _TabElem(title: '数据详情', child: const DataDetailPage()),
 ];

+ 298 - 0
lib/view/home/personal_rank/personal_rank.dart

@@ -0,0 +1,298 @@
+import 'package:application/service/map_watch.dart';
+import 'package:common_pub/utils.dart';
+import 'package:get/get.dart';
+import 'package:flutter/material.dart';
+import '../../../widget/title_point.dart';
+
+class PersonalRankController extends GetxController {
+  @override
+  void onInit() {
+    super.onInit();
+    final map = MapWatchService.instance;
+    if (map != null) {
+      activeList.bindStream(map.activeList.stream);
+    }
+  }
+
+  final activeList = <ActiveInfo>[].obs;
+  final Rx<ActiveInfo?> selectActive = Rx(null);
+}
+
+class PersonalRankPage extends StatelessWidget {
+  const PersonalRankPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return GetBuilder(
+        init: PersonalRankController(),
+        builder: (c) {
+          return Container(
+            width: double.infinity,
+            height: double.infinity,
+            margin: const EdgeInsets.all(20),
+            padding: const EdgeInsets.fromLTRB(12, 17, 12, 17),
+            decoration: BoxDecoration(
+                color: Colors.transparent,
+                borderRadius: BorderRadius.circular(16)),
+            child: DefaultTextStyle(
+                style: const TextStyle(color: Colors.white),
+                child: Row(
+                  children: [
+                    SizedBox(
+                        width: 260,
+                        height: double.infinity,
+                        child: Obx(() => eActiveList(context, c))),
+                    const SizedBox(width: 20),
+                    Expanded(child: Obx(() => eUserList(context, c)))
+                  ],
+                )),
+          );
+        });
+  }
+
+  Widget titlePoint() {
+    return const TitlePoint(color: Color(0xff98d8ff));
+  }
+
+  Widget eActiveList(BuildContext context, PersonalRankController c) {
+    return Column(
+      children: [
+        Row(
+          children: [
+            Padding(padding: const EdgeInsets.all(8), child: titlePoint()),
+            Text('活动列表',
+                style: context.textTheme.titleLarge
+                    ?.copyWith(color: Colors.white)),
+            const Spacer(),
+            Container(
+              decoration: BoxDecoration(
+                  border: Border.all(color: const Color(0xffe3e3e3))),
+              child: const Text('2023-06-26'),
+            )
+          ],
+        ),
+        const SizedBox(height: 20),
+        Expanded(
+            child: Container(
+                padding: const EdgeInsets.all(12),
+                decoration: BoxDecoration(
+                    color: const Color(0xff003656),
+                    borderRadius: BorderRadius.circular(9)),
+                child: ListView(
+                  children: c.activeList
+                      .map((e) => wActiveCard(
+                              context, e, c.selectActive.value?.id == e.id, () {
+                            c.selectActive.value = e;
+                          }))
+                      .toList(),
+                ))),
+      ],
+    );
+  }
+
+  Widget wActiveCard(BuildContext context, ActiveInfo active, bool selected,
+      VoidCallback onTap) {
+    return GestureDetector(
+        onTap: onTap,
+        child: Container(
+          decoration: const BoxDecoration(color: Color(0xff00a0ff), boxShadow: [
+            BoxShadow(color: Color(0x4d000000), blurRadius: 3.5)
+          ]),
+          height: _cardHeight,
+          width: double.infinity,
+          margin: const EdgeInsets.only(top: 7),
+          padding: const EdgeInsets.only(right: 11),
+          child: Row(
+            children: [
+              Container(
+                margin: const EdgeInsets.only(right: 10),
+                height: double.infinity,
+                width: 6.4,
+                color: selected ? const Color(0xffff870d) : Colors.transparent,
+              ),
+              Text(active.name),
+              const Spacer(),
+              Text(active.userList.length.toString())
+            ],
+          ),
+        ));
+  }
+
+  Widget eUserList(BuildContext context, PersonalRankController c) {
+    final active = c.selectActive.value;
+
+    if (active == null) {
+      return const SizedBox();
+    }
+
+    final userList = c.selectActive.value?.userList ?? <UserInfo>[];
+
+    return Column(
+      children: [
+        Row(
+          children: [
+            const Padding(padding: EdgeInsets.all(8), child: TitlePoint()),
+            Text('个人排名',
+                style: context.textTheme.titleLarge
+                    ?.copyWith(color: Colors.white)),
+            Text(' (${active.name})',
+                style: context.textTheme.titleLarge
+                    ?.copyWith(color: const Color(0xffffcb00))),
+          ],
+        ),
+        Expanded(
+            child: Padding(
+                padding: const EdgeInsets.all(18),
+                child: Column(
+                  children: [
+                    eUserListTitle(context),
+                    Expanded(
+                        child: ListView(
+                      children: userList.indexed.map<Widget>((t) {
+                        return eUserCard(context, c, t.$1 + 1, t.$2);
+                      }).toList(),
+                    ))
+                  ],
+                )))
+      ],
+    );
+  }
+
+  Widget eUserListTitle(BuildContext context) {
+    return DefaultTextStyle(
+        style: const TextStyle(
+            color: Color(0xff98d8ff),
+            fontSize: 20,
+            fontWeight: FontWeight.w700),
+        child: Row(
+          children: [
+            const SizedBox(
+                width: _userIndexWidth,
+                child: Text('排名', textAlign: TextAlign.center)),
+            const SizedBox(width: 4),
+            const SizedBox(
+                width: _userNameWidth,
+                child: Text('用户名', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+            const Expanded(child: Text('路线ID', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+            const SizedBox(
+                width: _userTimeWidth,
+                child: Text('总时间', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+            const Expanded(
+                child: Text('总里程', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+            const Expanded(
+                child: Text('配速', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+            const SizedBox(
+                width: _userResultWidth,
+                child: Text('分组', textAlign: TextAlign.center)),
+            verticalDivider(show: false),
+          ],
+        ));
+  }
+
+  Widget eUserCard(BuildContext context, PersonalRankController c, int index,
+      UserInfo data) {
+    var startAt = '--';
+    if (data.startAt != null) {
+      startAt = data.startAt!.toIso8601String();
+    }
+
+    return DefaultTextStyle(
+        style: context.textTheme.bodyMedium!.copyWith(color: Colors.white),
+        child: Container(
+          height: _cardHeight,
+          width: double.infinity,
+          margin: const EdgeInsets.only(top: 3),
+          child: Row(children: [
+              Container(
+                  width: _userIndexWidth,
+                  height:double.infinity,
+                  decoration: const BoxDecoration(
+                    color: Color(0xffff870d),
+                    borderRadius: BorderRadius.only(topLeft: Radius.circular(6), bottomLeft: Radius.circular(6))
+                  ),
+                  alignment: Alignment.center,
+                  child: Text(
+                    index.toString(),
+                    textAlign: TextAlign.center,
+                    style: const TextStyle(fontSize: 34, fontWeight: FontWeight.w700, fontStyle: FontStyle.italic),
+                  )),
+              const SizedBox(width: 4),
+              Expanded(child: Container(
+                height: double.infinity,
+                decoration: const BoxDecoration(
+                    color: Color(0xff003656),
+                    borderRadius: BorderRadius.only(topRight: Radius.circular(6), bottomRight: Radius.circular(6))
+                ),
+                child: Row(
+                  children: [
+                    SizedBox(
+                        width: _userNameWidth,
+                        child: Text(
+                          data.name,
+                          textAlign: TextAlign.center,
+                        )),
+                    verticalDivider(),
+                    Expanded(
+                        child: Text(
+                          data.routeName,
+                          textAlign: TextAlign.center,
+                        )),
+                    verticalDivider(),
+                    SizedBox(
+                        width: _userTimeWidth,
+                        child: Text(
+                          data.duration.toMinSecondString(),
+                          textAlign: TextAlign.center,
+                        )),
+                    verticalDivider(),
+                    Expanded(
+
+                        child: Text(
+                          data.distance.toString(),
+                          textAlign: TextAlign.center,
+                        )),
+                    verticalDivider(),
+                    Expanded(
+                        child: Container(
+                          margin: EdgeInsets.only(left: 8, right: 8),
+                          alignment: Alignment.center,
+                          height: 18,
+                          decoration: BoxDecoration(color: data.pace.color, borderRadius: BorderRadius.circular(9)),
+                          child: Text(
+                            data.pace.toString(),
+                            textAlign: TextAlign.center,
+                          )
+                        ) ),
+                    verticalDivider(),
+                    Container(
+                      alignment: Alignment.center,
+                        width: _userResultWidth,
+                        child: Icon(Icons.flag, color: data.flag.value.color)),
+                  ],
+                ),
+              ))
+            ],
+          )
+        ));
+  }
+
+  Widget verticalDivider({bool show = true}){
+    return VerticalDivider(
+      width: 3,
+      indent: 14,
+      endIndent: 14,
+      color: show? Colors.white: Colors.transparent,
+    );
+  }
+
+  static const _userIndexWidth = 56.0;
+  static const _userNameWidth = 84.0;
+  static const _userResultWidth = 52.0;
+  static const _userTimeWidth = 62.0;
+  static const _cardHeight = 45.0;
+}

+ 5 - 3
lib/widget/title_point.dart

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