import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:location/base/base_page.dart'; import 'package:location/data/bean/user_info.dart'; import 'package:location/module/main/main_controller.dart'; import 'package:location/module/main/today_track_helper.dart'; import 'package:location/module/main/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:sliding_sheet2/sliding_sheet2.dart'; import 'package:visibility_detector/visibility_detector.dart'; import '../../data/consts/constants.dart'; import '../../router/app_pages.dart'; import '../../utils/common_style.dart'; import '../../utils/common_util.dart'; import '../../widget/marquee_text.dart'; import '../../widget/relative_time_text.dart'; import 'main_friend_item.dart'; class MainPage extends BasePage { const MainPage({super.key}); static start({bool? isNotClear, Map? arguments}) { if (isNotClear == null || !isNotClear) { Get.offAllNamed(RoutePath.mainTab, arguments: arguments); } else { Get.toNamed(RoutePath.mainTab, arguments: arguments); } } @override bool immersive() { return true; } @override Widget buildBody(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (bool didPop, dynamic result) { controller.onAppBack(); }, child: Column( children: [ Expanded( child: Stack( children: [ buildMapView(), buildMapFunView(), buildMainBottomView(), buildFriendListView(), ], )), buildTabContainer() ], ), ); } Widget buildMapView() { return Padding( padding: EdgeInsets.only(bottom: 50.h), child: SizedBox( width: double.infinity, child: MapWidget( controller: controller.mapController, onMarkerTap: controller.onMarkerTap, )), ); } Widget buildMainBottomView() { return SlidingSheet( color: '#F9F9F9'.color, elevation: 10, shadowColor: Colors.black.withOpacity(0.1), cornerRadius: 18.w, snapSpec: SnapSpec( initialSnap: SnapSpec.headerSnap, // Enable snapping. This is true by default. snap: true, // Set custom snapping points. snappings: [SnapSpec.headerSnap, SnapSpec.expanded], // Define to what the snappings relate to. In this case, // the total available space that the sheet can expand to. positioning: SnapPositioning.relativeToAvailableSpace, ), headerBuilder: buildHeaderBuilder, builder: buildTrackEntranceBuilder, ); } Widget buildTrackEntranceBuilder(BuildContext context, SheetState state) { return VisibilityDetector( key: Key('main_today_track'), onVisibilityChanged: (VisibilityInfo info) { final visibleFraction = info.visibleFraction; controller.onFriendVisibleFraction(visibleFraction); }, child: AspectRatio( aspectRatio: 336 / 134, child: Container( margin: EdgeInsets.only(left: 12.w, right: 12.w, bottom: 12.w), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20.r)), child: Obx(() { final todayTrack = controller.selectedFriend?.id == null ? null : controller .todayTrackReportMap[controller.selectedFriend?.id]; if (controller.memberStatusInfo.value == null || controller.memberStatusInfo.value?.expired == true) { return buildNoMemberView(); } else if (todayTrack == null || todayTrack.isRequestSuccess.value == false) { return buildTodayTrackLoadingView(); } else { return buildTodayTrackDetailView(todayTrack); } })), ), ); } Widget buildNoMemberView() { return GestureDetector( onTap: controller.onTrackNoMemberClick, child: Assets.images.imgTrackNoMemberTips.image(fit: BoxFit.fill)); } Widget buildTodayTrackLoadingView() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CupertinoActivityIndicator( color: '#A3A3A5'.color, radius: 16.w, ), SizedBox(height: 15.w), Text(StringName.mainTodayTrackLoading, style: TextStyle( fontSize: 14.sp, color: '#666666'.color.withOpacity(0.87))) ], ); } Widget buildTodayTrackDetailView(TodayTrackReportBean todayTrackReportBean) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: controller.onTodayTraceClick, child: Padding( padding: EdgeInsets.only(left: 12.w, right: 12.w, top: 12.w, bottom: 9.w), child: Column( children: [ Row( children: [ Text(StringName.todaySimpleTrack, style: TextStyle( fontSize: 13.sp, color: '#333333'.color, fontWeight: FontWeight.bold)), Spacer(), Assets.images.iconMainTrackArrow .image(width: 10.w, height: 10.w), ], ), SizedBox(height: 7.w), buildSelectedFriendTodayTrackDetailView(todayTrackReportBean), ], ), ), ); } Widget buildSelectedFriendTodayTrackDetailView( TodayTrackReportBean todayTrackReportBean) { final startAddr = todayTrackReportBean.startPoint?.addr; final errorAddr = todayTrackReportBean.exceptionPoint?.addr; MainTrackType startPointType = startAddr?.isNotEmpty == true ? MainTrackType.startPoint : MainTrackType.normalPoint; MainTrackType errorPointType = errorAddr?.isNotEmpty == true ? MainTrackType.errorPoint : MainTrackType.normalPoint; Color startPointColor; if (startPointType == MainTrackType.startPoint) { startPointColor = '#15CBA1'.color; } else if (startPointType == MainTrackType.errorPoint) { startPointColor = '#E94949'.color; } else { startPointColor = '#D6D6D6'.color; } Color errorPointColor; if (errorPointType == MainTrackType.errorPoint) { errorPointColor = '#E94949'.color; } else { errorPointColor = '#D6D6D6'.color; } return Expanded( child: Row( children: [ Container( margin: EdgeInsets.only(bottom: 3.w, top: 3.w), child: AspectRatio( aspectRatio: 1, child: buildTodayMapView(todayTrackReportBean), ), ), SizedBox(width: 10.w), Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox(height: 6.w), getMainTrackDot(startPointColor), Expanded( child: Container( margin: EdgeInsets.symmetric(vertical: 4.w), width: 1.w, height: double.infinity, decoration: BoxDecoration( color: '#F0F0F0'.color, borderRadius: BorderRadius.circular(100.r), ), ), ), getMainTrackDot(errorPointColor), SizedBox(height: 6.w), ], ), SizedBox(width: 8.w), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Visibility( visible: startPointType == MainTrackType.normalPoint, child: SizedBox(height: 2.w)), buildTrackPoint(startPointType, startAddr ?? ''), Spacer(), buildTrackPoint(errorPointType, errorAddr ?? ''), Visibility( visible: errorPointType == MainTrackType.normalPoint, child: SizedBox(height: 5.w)) ], ), ) ], )); } Widget buildTodayMapView(TodayTrackReportBean todayTrackReportBean) { return ClipRRect( borderRadius: BorderRadius.circular(8.r), child: MapWidget( isShowLogo: false, interactionIsEnabled: false, mapPadding: todayTrackReportBean.mapPadding, markers: todayTrackReportBean.markers, polyline: todayTrackReportBean.polylines, )); } Widget buildFriendListView() { return SafeArea( child: Container( margin: EdgeInsets.only(top: 26.w), child: Row( children: [ Expanded(child: buildMainFriendList()), GestureDetector( onTap: () { controller.onAddFriendClick(); }, child: Container( margin: EdgeInsets.only(right: 16.w, left: 8.w), child: Assets.images.iconMainAddFriend .image(width: 60.w, height: 60.w)), ) ], ), ), ); } Widget buildMapFunView() { return Positioned( right: 0.w, bottom: 140.w, child: Column( children: [ GestureDetector( onTap: controller.onRefreshFriendLocationClick, child: Container( margin: EdgeInsets.only(right: 12.w), child: Assets.images.iconMainRefreshFriendLocation .image(width: 42.w, height: 42.w)), ), SizedBox(height: 14.w), GestureDetector( onTap: controller.onCurrentLocationClick, child: Container( margin: EdgeInsets.only(right: 12.w), child: Assets.images.iconMainRefreshMineLocation .image(width: 42.w, height: 42.w)), ), SizedBox(height: 20.w) ], ), ); } Container buildTabContainer() { return Container( decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(20.w), topRight: Radius.circular(20.w), ), boxShadow: [ BoxShadow( color: ColorName.black.withOpacity(0.01), blurRadius: 10, offset: const Offset(0, -2), // changes position of shadow ), ], ), padding: EdgeInsets.only(top: 13.w, bottom: 23.w), child: buildMainFunList()); } Widget buildMainFunList() { return Row( children: [ Expanded( child: buildFunItem( Assets.images.iconMainFriendGuard.provider(), StringName.mainFriendListTab, () => controller.onFriendClick())), Expanded(child: Obx(() { return buildFunItem(Assets.images.iconMainNews.provider(), StringName.mainNewsTab, () => controller.onNewsClick(), isShowDot: controller.hasUnreadMessage); })), Expanded( child: buildFunItem( Assets.images.iconMainHelp.provider(), StringName.mainHelpTab, () => controller.onUrgentContactClick())), Expanded( child: buildFunItem(Assets.images.iconMainMine.provider(), StringName.mainMineTab, () => controller.onMineClick())) ], ); } Widget buildFunItem(ImageProvider imgProvider, String title, Function() onTap, {bool? isShowDot}) { return GestureDetector( onTap: onTap, child: IntrinsicHeight( child: Column( children: [ Stack(children: [ SizedBox( width: 44.w, height: 44.w, child: Image(image: imgProvider)), Visibility( visible: isShowDot ?? false, child: Positioned( top: 6.w, right: 6.w, child: Container( width: 10.w, height: 10.w, decoration: BoxDecoration( shape: BoxShape.circle, color: '#FF333D'.color, // 背景颜色 ), ), ), ) ]), Text(title, style: TextStyle( fontSize: 12.sp, color: ColorName.black70, fontWeight: FontWeight.bold)) ], ), ), ); } Widget buildMainFriendList() { return SizedBox( height: 58.w, child: Obx(() { return ListView( physics: const BouncingScrollPhysics( parent: AlwaysScrollableScrollPhysics()), padding: EdgeInsets.only(left: 12.w), scrollDirection: Axis.horizontal, children: [ for (UserInfo userInfo in controller.integrateList) Obx(() { return mainFriendItem( userInfo, controller.selectedFriend?.id == userInfo.id, onTap: () { controller.onSelectUserClick(userInfo); }); }) ], ); }), ); } Widget buildFooterBuilder(BuildContext context, SheetState state) { return buildTabContainer(); } Widget buildHeaderBuilder(BuildContext context, SheetState state) { return IntrinsicHeight( child: Column( children: [ SizedBox(height: 5.w), Container( width: 32.w, height: 3.w, decoration: BoxDecoration( color: '#D9D9D9'.color, borderRadius: BorderRadius.all(Radius.circular(49.w))), ), SizedBox(height: 12.w), buildSelectFriendInfoView(), SizedBox(height: 13.w) ], ), ); } Widget buildSelectFriendInfoView() { return Container( width: 336.w, height: 86.w, decoration: BoxDecoration( color: ColorName.white, borderRadius: BorderRadius.all(Radius.circular(20.w))), child: Row( children: [ SizedBox(width: 7.w), Obx(() { return buildCustomAvatarOrDefaultAvatarView( size: 50.w, avatar: controller.selectedFriend?.avatar, isMine: controller.selectedFriend?.isMine == true); }), SizedBox(width: 5.w), Expanded( child: Container( margin: EdgeInsets.symmetric(vertical: 15.w), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Obx(() { return Text( controller.selectedFriend?.getUserNickName() ?? '', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16.sp, color: '#202020'.color), ); }), SizedBox(width: 7.w), Obx(() { return RelativeTimeText( timestamp: controller.selectedFriend?.lastLocation .value?.lastUpdateTime, updateInterval: Duration(minutes: 1), style: TextStyle( fontSize: 12.sp, color: '#A7A7A7'.color)); }), Spacer(), Obx(() { return controller.selectedFriend != null ? GestureDetector( onTap: () => controller.onViewTraceClick( controller.selectedFriend!), child: Container( margin: EdgeInsets.only(right: 16.w), decoration: getPrimaryBtnDecoration(32.w), padding: EdgeInsets.symmetric( horizontal: 21.w, vertical: 5.w), child: Text(StringName.locationTrace, style: TextStyle( fontSize: 15.sp, color: Colors.white))), ) : SizedBox.shrink(); }), ], ), Expanded( child: Container( margin: EdgeInsets.only(right: 17.w), child: Obx(() { return ImageFiltered( enabled: controller.selectedFriend?.blockedMe == true || ((controller.memberStatusInfo.value == null || controller.memberStatusInfo.value ?.expired == true) && !(controller.selectedFriend?.isMine == true)), imageFilter: ImageFilter.blur( sigmaX: Constants.blurredX, sigmaY: Constants.blurredY, ), child: controller.selectedFriend?.blockedMe == true || ((controller.memberStatusInfo.value == null || controller.memberStatusInfo.value?.expired == true) && !(controller.selectedFriend?.isMine == true)) ? Text(addressCheck(controller.selectedFriend?.lastLocation.value?.address), style: TextStyle( fontSize: 13.sp, color: ColorName.black50)) : MarqueeText.marquee( text: addressCheck(controller.selectedFriend ?.lastLocation.value?.address), textStyle: TextStyle( fontSize: 13.sp, color: ColorName.black50), containerWidth: 244.w), ); }), ), ) // Text('广东省广州市天河区XX街街XX街区XX村XX') ], ), ), ) ], )); } }