track_page.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. import 'package:flutter/cupertino.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/src/widgets/framework.dart';
  4. import 'package:flutter_map/flutter_map.dart';
  5. import 'package:flutter_screenutil/flutter_screenutil.dart';
  6. import 'package:get/get.dart';
  7. import 'package:get/get_core/src/get_main.dart';
  8. import 'package:location/base/base_page.dart';
  9. import 'package:location/data/bean/user_info.dart';
  10. import 'package:location/module/track/track_controller.dart';
  11. import 'package:location/resource/assets.gen.dart';
  12. import 'package:location/resource/colors.gen.dart';
  13. import 'package:location/resource/string.gen.dart';
  14. import 'package:location/utils/common_expand.dart';
  15. import 'package:location/utils/common_style.dart';
  16. import 'package:location/utils/date_util.dart';
  17. import 'package:sliding_sheet2/sliding_sheet2.dart';
  18. import '../../router/app_pages.dart';
  19. import '../../widget/common_view.dart';
  20. import '../../widget/relative_time_text.dart';
  21. class TrackPage extends BasePage<TrackController> {
  22. const TrackPage({super.key});
  23. static void start(UserInfo userInfo) {
  24. Get.toNamed(RoutePath.track, arguments: userInfo);
  25. }
  26. @override
  27. bool immersive() {
  28. return true;
  29. }
  30. @override
  31. Widget buildBody(BuildContext context) {
  32. return Stack(
  33. children: [
  34. SizedBox(
  35. width: double.infinity,
  36. height: double.infinity,
  37. child: MapWidget(
  38. controller: controller.mapController,
  39. ),
  40. ),
  41. SafeArea(
  42. child: Container(
  43. margin: EdgeInsets.only(top: 14.w, left: 12.w),
  44. child: GestureDetector(
  45. onTap: controller.back, child: CommonView.getBackBtnView()),
  46. ),
  47. ),
  48. SlidingSheet(
  49. controller: controller.sheetController,
  50. elevation: 10,
  51. shadowColor: Colors.black.withOpacity(0.1),
  52. cornerRadius: 18.w,
  53. snapSpec: SnapSpec(
  54. initialSnap: 1,
  55. // Enable snapping. This is true by default.
  56. snap: true,
  57. // Set custom snapping points.
  58. snappings: [168 / Get.height, 1.0],
  59. // Define to what the snappings relate to. In this case,
  60. // the total available space that the sheet can expand to.
  61. positioning: SnapPositioning.relativeToAvailableSpace,
  62. ),
  63. footerBuilder: (context, state) {
  64. return buildOperationBtn();
  65. },
  66. builder: (context, state) {
  67. return Column(
  68. children: [
  69. SizedBox(height: 5.w),
  70. Align(
  71. alignment: Alignment.center,
  72. child: Container(
  73. width: 32.w,
  74. height: 3.w,
  75. decoration: BoxDecoration(
  76. color: '#D9D9D9'.color,
  77. borderRadius: BorderRadius.circular(49.w),
  78. ),
  79. ),
  80. ),
  81. SizedBox(height: 25.w),
  82. buildTrackHeaderView(),
  83. SizedBox(
  84. width: double.infinity,
  85. height: 220.w,
  86. child: TabBarView(
  87. controller: controller.tabController,
  88. children: [
  89. buildTrackHistoryContentView(),
  90. buildTrackNowContentView()
  91. ]),
  92. )
  93. ],
  94. );
  95. },
  96. )
  97. ],
  98. );
  99. }
  100. Widget buildOperationBtn() {
  101. return GestureDetector(
  102. onTap: controller.onTrackQueryClick,
  103. child: Container(
  104. margin: EdgeInsets.only(bottom: 18.w, top: 9.w),
  105. child: Row(
  106. mainAxisAlignment: MainAxisAlignment.center,
  107. children: [
  108. Obx(() {
  109. return GestureDetector(
  110. onTap: controller.onTraceDetailClick,
  111. child: AnimatedOpacity(
  112. opacity: controller.currentIndex == 0 ? 1 : 0,
  113. duration: Duration(milliseconds: 250),
  114. child: AnimatedContainer(
  115. width: controller.currentIndex == 0 &&
  116. controller.isShowTraceDetailBtn
  117. ? 152.w
  118. : 0.w,
  119. height: 46.w,
  120. decoration: BoxDecoration(
  121. color: '#147B7DFF'.color,
  122. border:
  123. Border.all(color: ColorName.colorPrimary, width: 1.w),
  124. borderRadius: BorderRadius.circular(46.w),
  125. ),
  126. duration: Duration(milliseconds: 250),
  127. child: Center(
  128. child: Text(
  129. maxLines: 1,
  130. StringName.traceDetail,
  131. style: TextStyle(
  132. fontSize: 14.sp, color: ColorName.colorPrimary),
  133. ),
  134. ),
  135. ),
  136. ),
  137. );
  138. }),
  139. // Obx(() {
  140. // return Visibility(
  141. // visible: controller.currentIndex == 0 &&
  142. // controller.isShowTraceDetailBtn,
  143. // child: SizedBox(width: 18.w));
  144. // }),
  145. Obx(() {
  146. double width = 152.w;
  147. if (controller.currentIndex == 1) {
  148. width = 322.w;
  149. } else if (controller.isShowTraceDetailBtn) {
  150. width = 152.w;
  151. } else {
  152. width = 322.w;
  153. }
  154. return AnimatedContainer(
  155. margin: EdgeInsets.only(
  156. left: controller.currentIndex == 0 &&
  157. controller.isShowTraceDetailBtn
  158. ? 18.w
  159. : 0),
  160. duration: Duration(milliseconds: 250),
  161. width: width,
  162. height: 46.w,
  163. decoration: getPrimaryBtnDecoration(46.w),
  164. child: Center(
  165. child: Obx(() {
  166. return Text(
  167. controller.currentIndex == 0
  168. ? StringName.trackQueryPath
  169. : StringName.trackNowLocation,
  170. style: TextStyle(fontSize: 14.sp, color: Colors.white),
  171. );
  172. }),
  173. ),
  174. );
  175. })
  176. ],
  177. ),
  178. ),
  179. );
  180. }
  181. Widget buildTrackHeaderView() {
  182. return Row(
  183. children: [
  184. SizedBox(width: 14.w),
  185. Obx(() {
  186. return Image(
  187. image: controller.userInfo?.isMine == true
  188. ? Assets.images.iconDefaultMineAvatar.provider()
  189. : Assets.images.iconDefaultFriendAvatar.provider(),
  190. width: 32.w,
  191. height: 32.w);
  192. }),
  193. SizedBox(width: 10.w),
  194. Expanded(
  195. child: Text(
  196. '${controller.userInfo?.getUserNickName() ?? ''}的轨迹',
  197. style: TextStyle(
  198. overflow: TextOverflow.ellipsis,
  199. fontSize: 16.sp,
  200. color: ColorName.black80,
  201. fontWeight: FontWeight.bold),
  202. ),
  203. ),
  204. buildOperationTabBar(),
  205. SizedBox(width: 12.w),
  206. ],
  207. );
  208. }
  209. Widget buildOperationTabBar() {
  210. return IntrinsicWidth(
  211. child: Container(
  212. padding: EdgeInsets.all(2.w),
  213. decoration: BoxDecoration(
  214. color: '#F3F3F3'.color,
  215. borderRadius: BorderRadius.circular(48.w),
  216. ),
  217. height: 32.w,
  218. child: TabBar(
  219. controller: controller.tabController,
  220. indicator: BoxDecoration(
  221. color: ColorName.colorPrimary,
  222. borderRadius: BorderRadius.circular(48.w),
  223. ),
  224. dividerHeight: 0,
  225. indicatorSize: TabBarIndicatorSize.tab,
  226. unselectedLabelStyle:
  227. TextStyle(fontSize: 14.sp, color: '#666666'.color),
  228. labelStyle: TextStyle(fontSize: 14.sp, color: ColorName.white),
  229. tabs: [
  230. Tab(text: StringName.trackHistory),
  231. Tab(text: StringName.trackNowLocation)
  232. ],
  233. ),
  234. ),
  235. );
  236. }
  237. Widget buildTrackHistoryContentView() {
  238. return Column(
  239. children: [
  240. SizedBox(height: 10.w),
  241. Builder(builder: (context) {
  242. return GestureDetector(
  243. onTap: () {
  244. controller.onTrackStartTimeClick(context);
  245. },
  246. child: Padding(
  247. padding: EdgeInsets.symmetric(vertical: 9.w),
  248. child: Row(
  249. children: [
  250. SizedBox(width: 14.w),
  251. Text(
  252. StringName.trackStartTime,
  253. style: TextStyle(
  254. fontSize: 14.sp,
  255. color: ColorName.black80,
  256. fontWeight: FontWeight.bold),
  257. ),
  258. Spacer(),
  259. Obx(() {
  260. return Text(
  261. controller.trackStartTime?.format('yyyy-MM-dd HH:mm') ??
  262. '',
  263. style:
  264. TextStyle(fontSize: 14.sp, color: ColorName.black50),
  265. );
  266. }),
  267. SizedBox(width: 6.w),
  268. Assets.images.iconTrackSelectTimeArrow
  269. .image(width: 16.w, height: 16.w),
  270. SizedBox(width: 14.w),
  271. ],
  272. ),
  273. ),
  274. );
  275. }),
  276. Builder(builder: (context) {
  277. return GestureDetector(
  278. onTap: () {
  279. controller.onTrackEndTimeClick(context);
  280. },
  281. child: Padding(
  282. padding: EdgeInsets.symmetric(vertical: 9.w),
  283. child: Row(
  284. children: [
  285. SizedBox(width: 14.w),
  286. Text(
  287. StringName.trackEndTime,
  288. style: TextStyle(
  289. fontSize: 14.sp,
  290. color: ColorName.black80,
  291. fontWeight: FontWeight.bold),
  292. ),
  293. Spacer(),
  294. Obx(() {
  295. return Text(
  296. controller.trackEndTime?.format('yyyy-MM-dd HH:mm') ?? '',
  297. style:
  298. TextStyle(fontSize: 14.sp, color: ColorName.black50),
  299. );
  300. }),
  301. SizedBox(width: 6.w),
  302. Assets.images.iconTrackSelectTimeArrow
  303. .image(width: 16.w, height: 16.w),
  304. SizedBox(width: 14.w),
  305. ],
  306. ),
  307. ),
  308. );
  309. }),
  310. SizedBox(height: 12.w),
  311. Obx(() {
  312. return Visibility(
  313. visible: controller.startAddress != null ||
  314. controller.endAddress != null,
  315. child: Container(
  316. padding: EdgeInsets.all(12.w),
  317. margin: EdgeInsets.symmetric(horizontal: 14.w),
  318. width: double.infinity,
  319. decoration: BoxDecoration(
  320. color: '#E5F8F8F8'.color,
  321. borderRadius: BorderRadius.circular(12.w),
  322. ),
  323. child: Column(
  324. children: [
  325. buildAddressInfoView(
  326. '#12C172'.color,
  327. StringName.trackStartLocation,
  328. controller.startAddress ?? ''),
  329. Align(
  330. alignment: Alignment.centerLeft,
  331. child: Container(
  332. margin: EdgeInsets.only(left: 3.5.w),
  333. child: Assets.images.bgTrackLocationTie
  334. .image(width: 1.5.w))),
  335. buildAddressInfoView(
  336. '#F3353A'.color,
  337. StringName.trackEndLocation,
  338. controller.endAddress ?? ''),
  339. ],
  340. )),
  341. );
  342. })
  343. ],
  344. );
  345. }
  346. Widget buildAddressInfoView(Color color, String title, String content) {
  347. return Row(
  348. children: [
  349. Container(
  350. width: 10.w,
  351. height: 10.w,
  352. decoration: BoxDecoration(
  353. shape: BoxShape.circle,
  354. border: Border.all(color: color, width: 2.w),
  355. ),
  356. ),
  357. SizedBox(width: 11.w),
  358. Text(title,
  359. style: TextStyle(
  360. fontSize: 13.sp,
  361. color: ColorName.black80,
  362. fontWeight: FontWeight.bold)),
  363. Expanded(
  364. child: Text(content,
  365. style: TextStyle(fontSize: 13.sp, color: ColorName.black70)),
  366. )
  367. ],
  368. );
  369. }
  370. Widget buildTrackNowContentView() {
  371. return Column(
  372. children: [
  373. SizedBox(height: 20.w),
  374. Row(
  375. children: [
  376. SizedBox(width: 12.w),
  377. Assets.images.iconTrackLocationNow.image(width: 20.w, height: 20.w),
  378. SizedBox(width: 3.w),
  379. Obx(() {
  380. return RelativeTimeText(
  381. startPerchText: '当前位置·',
  382. endPerchText:
  383. controller.currentLocation?.lastUpdateTime == null
  384. ? ''
  385. : '更新',
  386. timestamp: controller.currentLocation?.lastUpdateTime,
  387. updateInterval: Duration(minutes: 1),
  388. style: TextStyle(
  389. fontSize: 15.sp,
  390. color: '#333333'.color,
  391. fontWeight: FontWeight.bold));
  392. })
  393. ],
  394. ),
  395. SizedBox(height: 16.w),
  396. Container(
  397. width: double.infinity,
  398. margin: EdgeInsets.symmetric(horizontal: 12.w),
  399. padding: EdgeInsets.all(14.w),
  400. decoration: BoxDecoration(
  401. color: '#F9F9F9'.color,
  402. borderRadius: BorderRadius.circular(6.w),
  403. ),
  404. child: Obx(() {
  405. return Text(controller.currentLocation?.address ?? '--',
  406. style: TextStyle(fontSize: 14.sp, color: '#666666'.color));
  407. }),
  408. )
  409. ],
  410. );
  411. }
  412. }