import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:get/get_core/src/get_main.dart'; import 'package:location/base/base_page.dart'; import 'package:location/data/bean/user_info.dart'; import 'package:location/module/track/track_controller.dart'; import 'package:location/module/track/track_day_detail/track_day_detail_view.dart'; import 'package:location/resource/assets.gen.dart'; import 'package:location/resource/colors.gen.dart'; import 'package:location/resource/string.gen.dart'; import 'package:location/utils/common_expand.dart'; import 'package:location/utils/common_style.dart'; import 'package:location/utils/date_util.dart'; import 'package:sliding_sheet2/sliding_sheet2.dart'; import '../../router/app_pages.dart'; import '../../utils/fixed_size_tab_indicator.dart'; import '../../widget/common_view.dart'; import '../../widget/relative_time_text.dart'; class TrackPage extends BasePage { const TrackPage({super.key}); static void start(UserInfo userInfo) { Get.toNamed(RoutePath.track, arguments: userInfo); } @override bool immersive() { return true; } @override Widget buildBody(BuildContext context) { return Stack( children: [ SizedBox( width: double.infinity, height: double.infinity, child: MapWidget( controller: controller.mapController, ), ), buildBackBtnView(), SlidingSheet( color: ColorName.white, controller: controller.sheetController, elevation: 10, shadowColor: Colors.black.withOpacity(0.1), cornerRadius: 18.w, snapSpec: SnapSpec( initialSnap: 0.45, // Enable snapping. This is true by default. snap: true, // Set custom snapping points. snappings: [SnapSpec.headerSnap, 0.45, 1.0], // Define to what the snappings relate to. In this case, // the total available space that the sheet can expand to. positioning: SnapPositioning.relativeToAvailableSpace, ), headerBuilder: (context, state) { return buildSheetHeadView(); }, builder: (context, state) { return buildSheetContentView(); }, ) ], ); } Widget buildBackBtnView() { return SafeArea( child: GestureDetector( onTap: controller.back, child: Container( margin: EdgeInsets.only(top: 14.w, left: 12.w), decoration: BoxDecoration(boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10.w, offset: Offset(0, 2.w), ), ]), child: CommonView.getBackBtnView(), ), ), ); } Widget buildSheetContentView() { return SizedBox( height: 0.77.sh, width: double.infinity, child: Obx(() { return DefaultTabController( length: controller.daysList.length, child: Column( children: [ SizedBox( width: double.infinity, child: TabBar( tabAlignment: TabAlignment.start, isScrollable: true, dividerHeight: 0, indicator: FixedSizeTabIndicator( width: 26.w, height: 3.w, radius: 0, color: ColorName.colorPrimary), unselectedLabelStyle: TextStyle(fontSize: 13.sp, color: '#666666'.color), labelStyle: TextStyle( fontSize: 13.sp, color: '#333333'.color, fontWeight: FontWeight.bold), tabs: controller.daysList.map((e) { return Tab( text: e.day, ); }).toList(), ), ), Container( color: '#EEEEEE'.color, height: 1.w, width: double.infinity, ), Expanded( child: TabBarView( children: List.generate( controller.daysList.length, (index) => TrackDayDetailView(controller.daysList[index], isExpand: index == 0)), )), ], ), ); }), ); } Widget buildSheetHeadView() { return IntrinsicHeight( child: Column( children: [ SizedBox(height: 5.w), Align( alignment: Alignment.center, child: Container( width: 32.w, height: 3.w, decoration: BoxDecoration( color: '#D9D9D9'.color, borderRadius: BorderRadius.circular(49.w), ), ), ), SizedBox(height: 25.w), buildTrackHeaderView(), SizedBox(height: 20.w), ], )); } Widget buildTrackHeaderView() { return Row( children: [ SizedBox(width: 14.w), Obx(() { return buildCustomAvatarOrDefaultAvatarView( size: 32.w, avatar: controller.userInfo?.avatar, isMine: controller.userInfo?.isMine == true); }), SizedBox(width: 10.w), Expanded( child: Text( '${controller.userInfo?.getUserNickName() ?? ''}的轨迹', style: TextStyle( overflow: TextOverflow.ellipsis, fontSize: 16.sp, color: ColorName.black80, fontWeight: FontWeight.bold), ), ), SizedBox(width: 12.w), ], ); } Widget buildTrackHistoryContentView() { return Column( children: [ SizedBox(height: 10.w), Builder(builder: (context) { return GestureDetector( onTap: () { controller.onTrackStartTimeClick(context); }, child: Padding( padding: EdgeInsets.symmetric(vertical: 9.w), child: Row( children: [ SizedBox(width: 14.w), Text( StringName.trackStartTime, style: TextStyle( fontSize: 14.sp, color: ColorName.black80, fontWeight: FontWeight.bold), ), Spacer(), Obx(() { return Text( controller.trackStartTime?.format('yyyy-MM-dd HH:mm') ?? '', style: TextStyle(fontSize: 14.sp, color: ColorName.black50), ); }), SizedBox(width: 6.w), Assets.images.iconTrackSelectTimeArrow .image(width: 16.w, height: 16.w), SizedBox(width: 14.w), ], ), ), ); }), Builder(builder: (context) { return GestureDetector( onTap: () { controller.onTrackEndTimeClick(context); }, child: Padding( padding: EdgeInsets.symmetric(vertical: 9.w), child: Row( children: [ SizedBox(width: 14.w), Text( StringName.trackEndTime, style: TextStyle( fontSize: 14.sp, color: ColorName.black80, fontWeight: FontWeight.bold), ), Spacer(), Obx(() { return Text( controller.trackEndTime?.format('yyyy-MM-dd HH:mm') ?? '', style: TextStyle(fontSize: 14.sp, color: ColorName.black50), ); }), SizedBox(width: 6.w), Assets.images.iconTrackSelectTimeArrow .image(width: 16.w, height: 16.w), SizedBox(width: 14.w), ], ), ), ); }), SizedBox(height: 12.w), Obx(() { return Visibility( visible: controller.startAddress != null || controller.endAddress != null, child: Container( padding: EdgeInsets.all(12.w), margin: EdgeInsets.symmetric(horizontal: 14.w), width: double.infinity, decoration: BoxDecoration( color: '#E5F8F8F8'.color, borderRadius: BorderRadius.circular(12.w), ), child: Column( children: [ buildAddressInfoView( '#12C172'.color, StringName.trackStartLocation, controller.startAddress ?? ''), Align( alignment: Alignment.centerLeft, child: Container( margin: EdgeInsets.only(left: 3.5.w), child: Assets.images.bgTrackLocationTie .image(width: 1.5.w))), buildAddressInfoView( '#F3353A'.color, StringName.trackEndLocation, controller.endAddress ?? ''), ], )), ); }) ], ); } Widget buildAddressInfoView(Color color, String title, String content) { return Row( children: [ Container( width: 10.w, height: 10.w, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all(color: color, width: 2.w), ), ), SizedBox(width: 11.w), Text(title, style: TextStyle( fontSize: 13.sp, color: ColorName.black80, fontWeight: FontWeight.bold)), Expanded( child: Text(content, style: TextStyle(fontSize: 13.sp, color: ColorName.black70)), ) ], ); } Widget buildTrackNowContentView() { return Column( children: [ SizedBox(height: 20.w), Row( children: [ SizedBox(width: 12.w), Assets.images.iconTrackLocationNow.image(width: 20.w, height: 20.w), SizedBox(width: 3.w), Obx(() { return RelativeTimeText( startPerchText: '当前位置·', endPerchText: controller.currentLocation?.lastUpdateTime == null ? '' : '更新', timestamp: controller.currentLocation?.lastUpdateTime, updateInterval: Duration(minutes: 1), style: TextStyle( fontSize: 15.sp, color: '#333333'.color, fontWeight: FontWeight.bold)); }) ], ), SizedBox(height: 16.w), Container( width: double.infinity, margin: EdgeInsets.symmetric(horizontal: 12.w), padding: EdgeInsets.all(14.w), decoration: BoxDecoration( color: '#F9F9F9'.color, borderRadius: BorderRadius.circular(6.w), ), child: Obx(() { return Text(controller.currentLocation?.address ?? '--', style: TextStyle(fontSize: 14.sp, color: '#666666'.color)); }), ) ], ); } }