|
|
@@ -0,0 +1,199 @@
|
|
|
+import 'package:flutter/cupertino.dart';
|
|
|
+import 'package:flutter/material.dart';
|
|
|
+import 'package:flutter/src/widgets/framework.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/module/track/track_detail/track_detail_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/router/app_pages.dart';
|
|
|
+import 'package:location/utils/common_expand.dart';
|
|
|
+import 'package:location/utils/date_util.dart';
|
|
|
+import 'package:location/widget/common_view.dart';
|
|
|
+
|
|
|
+import '../../../data/bean/atmob_track_point.dart';
|
|
|
+import '../../../utils/dashed_line_painter.dart';
|
|
|
+
|
|
|
+class TrackDetailPage extends BasePage<TrackDetailController> {
|
|
|
+ const TrackDetailPage({super.key});
|
|
|
+
|
|
|
+ static void start(List<AtmobTrackPoint>? points) {
|
|
|
+ Get.toNamed(RoutePath.trackDetail, arguments: points);
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget buildBody(BuildContext context) {
|
|
|
+ return Column(
|
|
|
+ children: [
|
|
|
+ CommonView.buildAppBar(StringName.traceDetail,
|
|
|
+ titleCenter: false, backOnTap: controller.back),
|
|
|
+ SizedBox(height: 12.w),
|
|
|
+ buildSearchView(),
|
|
|
+ Expanded(
|
|
|
+ child: CustomScrollView(slivers: [
|
|
|
+ SliverToBoxAdapter(
|
|
|
+ child: Container(
|
|
|
+ padding: EdgeInsets.only(left: 24.w, top: 32.w, bottom: 13.w),
|
|
|
+ child: Text(
|
|
|
+ StringName.traceDetailTitle,
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 15.sp,
|
|
|
+ color: '#202020'.color,
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Obx(() {
|
|
|
+ return SliverList.builder(
|
|
|
+ itemBuilder: buildTrackItem,
|
|
|
+ itemCount: controller.pointList.length);
|
|
|
+ })
|
|
|
+ ]))
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildSearchView() {
|
|
|
+ return Container(
|
|
|
+ width: double.infinity,
|
|
|
+ height: 52.w,
|
|
|
+ margin: EdgeInsets.symmetric(horizontal: 12.w),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: ColorName.white,
|
|
|
+ borderRadius: BorderRadius.circular(12.w),
|
|
|
+ border: Border.all(color: '#333738'.color, width: 1.w),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 16.w),
|
|
|
+ Assets.images.iconTrackSearch.image(width: 22.w, height: 22.w),
|
|
|
+ SizedBox(width: 6.w),
|
|
|
+ Expanded(
|
|
|
+ child: TextField(
|
|
|
+ onChanged: (txt) {
|
|
|
+ controller.onSearch(txt);
|
|
|
+ },
|
|
|
+ style: TextStyle(fontSize: 15.sp, color: ColorName.black90),
|
|
|
+ controller: controller.searchController,
|
|
|
+ maxLines: 1,
|
|
|
+ maxLength: 30,
|
|
|
+ keyboardType: TextInputType.text,
|
|
|
+ textAlignVertical: TextAlignVertical.center,
|
|
|
+ textInputAction: TextInputAction.next,
|
|
|
+ decoration: InputDecoration(
|
|
|
+ hintText: StringName.traceDetailSearchHint,
|
|
|
+ counterText: '',
|
|
|
+ hintStyle:
|
|
|
+ TextStyle(fontSize: 15.sp, color: "#A7A7A7".toColor()),
|
|
|
+ contentPadding: const EdgeInsets.all(0),
|
|
|
+ border:
|
|
|
+ const OutlineInputBorder(borderSide: BorderSide.none))),
|
|
|
+ ),
|
|
|
+ SizedBox(width: 16.w),
|
|
|
+ Obx(() {
|
|
|
+ return GestureDetector(
|
|
|
+ onTap: controller.onClearSearchTxt,
|
|
|
+ child: Visibility(
|
|
|
+ visible: controller.searchTxt.isNotEmpty,
|
|
|
+ child: Assets.images.iconTrackSearchClear
|
|
|
+ .image(width: 20.w, height: 20.w)),
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ SizedBox(width: 16.w),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget buildTrackItem(BuildContext context, int index) {
|
|
|
+ final item = controller.pointList[index];
|
|
|
+ bool isFirst = index == 0;
|
|
|
+ bool isLast = index == controller.pointList.length - 1;
|
|
|
+ bool isFirstPoint = item.traceType == TrackDetailController.lineStart;
|
|
|
+ bool isLastPoint = item.traceType == TrackDetailController.lineEnd;
|
|
|
+ return Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 24.w),
|
|
|
+ Column(
|
|
|
+ children: [
|
|
|
+ Visibility(
|
|
|
+ maintainSize: true,
|
|
|
+ maintainAnimation: true,
|
|
|
+ maintainState: true,
|
|
|
+ visible: !isFirst,
|
|
|
+ child: Padding(
|
|
|
+ padding: EdgeInsets.only(top: 1.w),
|
|
|
+ child: VerticalDashedLine(
|
|
|
+ dashSpace: 2.w,
|
|
|
+ color: '#F0F0F0'.color,
|
|
|
+ height: 35.w,
|
|
|
+ dashLength: 3.w,
|
|
|
+ strokeWidth: 1.w),
|
|
|
+ )),
|
|
|
+ SizedBox(height: 8.w),
|
|
|
+ SizedBox(
|
|
|
+ width: 20.w,
|
|
|
+ height: 20.w,
|
|
|
+ child: Builder(builder: (context) {
|
|
|
+ if (isFirstPoint) {
|
|
|
+ return Container(
|
|
|
+ margin: EdgeInsets.all(3.5.w),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ border:
|
|
|
+ Border.all(color: '#12C172'.color, width: 2.w),
|
|
|
+ shape: BoxShape.circle));
|
|
|
+ } else if (isLastPoint) {
|
|
|
+ return Container(
|
|
|
+ margin: EdgeInsets.all(3.5.w),
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ border:
|
|
|
+ Border.all(color: '#F3353A'.color, width: 2.w),
|
|
|
+ shape: BoxShape.circle));
|
|
|
+ } else {
|
|
|
+ return Assets.images.iconTrackLocation
|
|
|
+ .image(width: double.infinity, height: double.infinity);
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ SizedBox(height: 8.w),
|
|
|
+ Visibility(
|
|
|
+ maintainSize: true,
|
|
|
+ maintainAnimation: true,
|
|
|
+ maintainState: true,
|
|
|
+ visible: !isLastPoint,
|
|
|
+ child: VerticalDashedLine(
|
|
|
+ dashSpace: 2.w,
|
|
|
+ dashLength: 3.w,
|
|
|
+ color: '#F0F0F0'.color,
|
|
|
+ height: 35.w,
|
|
|
+ strokeWidth: 1.w)),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ SizedBox(width: 8.w),
|
|
|
+ Expanded(
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ item.addr ?? '',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 16.sp,
|
|
|
+ color: '#404040'.color,
|
|
|
+ fontWeight: FontWeight.bold),
|
|
|
+ ),
|
|
|
+ SizedBox(height: 4.w),
|
|
|
+ Text(
|
|
|
+ DateUtil.fromMillisecondsSinceEpoch(
|
|
|
+ "yyyy年MM月dd日 HH:mm", item.time),
|
|
|
+ style: TextStyle(fontSize: 13.sp, color: '#A7A7A7'.color)),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ SizedBox(width: 12.w),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|