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/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 '../../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, ), ), SafeArea( child: Container( margin: EdgeInsets.only(top: 14.w, left: 12.w), child: GestureDetector( onTap: controller.back, child: CommonView.getBackBtnView()), ), ), SlidingSheet( color: ColorName.white, controller: controller.sheetController, elevation: 10, shadowColor: Colors.black.withOpacity(0.1), cornerRadius: 18.w, snapSpec: SnapSpec( initialSnap: 1, // Enable snapping. This is true by default. snap: true, // Set custom snapping points. snappings: [SnapSpec.headerFooterSnap, 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, ), footerBuilder: (context, state) { return buildOperationBtn(); }, headerBuilder: (context, state) { 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(), ], )); }, builder: (context, state) { return Column( children: [ SizedBox( width: double.infinity, height: 220.w, child: TabBarView( controller: controller.tabController, children: [ buildTrackHistoryContentView(), buildTrackNowContentView() ]), ) ], ); }, ) ], ); } Widget buildOperationBtn() { return Container( margin: EdgeInsets.only(bottom: 18.w, top: 9.w), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() { return GestureDetector( onTap: controller.onTraceDetailClick, child: AnimatedOpacity( opacity: controller.currentIndex == 0 ? 1 : 0, duration: Duration(milliseconds: 250), child: AnimatedContainer( width: controller.currentIndex == 0 && controller.isShowTraceDetailBtn ? 152.w : 0.w, height: 46.w, decoration: BoxDecoration( color: '#147B7DFF'.color, border: Border.all(color: ColorName.colorPrimary, width: 1.w), borderRadius: BorderRadius.circular(46.w), ), duration: Duration(milliseconds: 250), child: Center( child: Text( maxLines: 1, StringName.traceDetail, style: TextStyle( fontSize: 14.sp, color: ColorName.colorPrimary), ), ), ), ), ); }), Obx(() { double width = 152.w; if (controller.currentIndex == 1) { width = 322.w; } else if (controller.isShowTraceDetailBtn) { width = 152.w; } else { width = 322.w; } return GestureDetector( onTap: controller.onTrackQueryClick, child: AnimatedContainer( margin: EdgeInsets.only( left: controller.currentIndex == 0 && controller.isShowTraceDetailBtn ? 18.w : 0), duration: Duration(milliseconds: 250), width: width, height: 46.w, decoration: getPrimaryBtnDecoration(46.w), child: Center( child: Obx(() { return Text( controller.currentIndex == 0 ? StringName.trackQueryPath : StringName.trackNowLocation, style: TextStyle(fontSize: 14.sp, color: Colors.white), ); }), ), ), ); }) ], ), ); } 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), ), ), buildOperationTabBar(), SizedBox(width: 12.w), ], ); } Widget buildOperationTabBar() { return IntrinsicWidth( child: Container( padding: EdgeInsets.all(2.w), decoration: BoxDecoration( color: '#F3F3F3'.color, borderRadius: BorderRadius.circular(48.w), ), height: 32.w, child: TabBar( controller: controller.tabController, indicator: BoxDecoration( color: ColorName.colorPrimary, borderRadius: BorderRadius.circular(48.w), ), dividerHeight: 0, indicatorSize: TabBarIndicatorSize.tab, unselectedLabelStyle: TextStyle(fontSize: 14.sp, color: '#666666'.color), labelStyle: TextStyle(fontSize: 14.sp, color: ColorName.white), tabs: [ Tab(text: StringName.trackHistory), Tab(text: StringName.trackNowLocation) ], ), ), ); } 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)); }), ) ], ); } }