track_page.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. width: 322.w,
  105. height: 46.w,
  106. margin: EdgeInsets.only(bottom: 18.w, top: 9.w),
  107. decoration: getPrimaryBtnDecoration(46.w),
  108. child: Center(
  109. child: Obx(() {
  110. return Text(
  111. controller.currentIndex == 0
  112. ? StringName.trackQueryPath
  113. : StringName.trackNowLocation,
  114. style: TextStyle(fontSize: 14.sp, color: Colors.white),
  115. );
  116. }),
  117. ),
  118. ),
  119. );
  120. }
  121. Widget buildTrackHeaderView() {
  122. return Row(
  123. children: [
  124. SizedBox(width: 14.w),
  125. Obx(() {
  126. return Image(
  127. image: controller.userInfo?.isMine == true
  128. ? Assets.images.iconDefaultMineAvatar.provider()
  129. : Assets.images.iconDefaultFriendAvatar.provider(),
  130. width: 32.w,
  131. height: 32.w);
  132. }),
  133. SizedBox(width: 10.w),
  134. Expanded(
  135. child: Text(
  136. '${controller.userInfo?.getUserNickName() ?? ''}的轨迹',
  137. style: TextStyle(
  138. overflow: TextOverflow.ellipsis,
  139. fontSize: 16.sp,
  140. color: ColorName.black80,
  141. fontWeight: FontWeight.bold),
  142. ),
  143. ),
  144. buildOperationTabBar(),
  145. SizedBox(width: 12.w),
  146. ],
  147. );
  148. }
  149. Widget buildOperationTabBar() {
  150. return IntrinsicWidth(
  151. child: Container(
  152. padding: EdgeInsets.all(2.w),
  153. decoration: BoxDecoration(
  154. color: '#F3F3F3'.color,
  155. borderRadius: BorderRadius.circular(48.w),
  156. ),
  157. height: 32.w,
  158. child: TabBar(
  159. controller: controller.tabController,
  160. indicator: BoxDecoration(
  161. color: ColorName.colorPrimary,
  162. borderRadius: BorderRadius.circular(48.w),
  163. ),
  164. dividerHeight: 0,
  165. indicatorSize: TabBarIndicatorSize.tab,
  166. unselectedLabelStyle:
  167. TextStyle(fontSize: 14.sp, color: '#666666'.color),
  168. labelStyle: TextStyle(fontSize: 14.sp, color: ColorName.white),
  169. tabs: [
  170. Tab(text: StringName.trackHistory),
  171. Tab(text: StringName.trackNowLocation)
  172. ],
  173. ),
  174. ),
  175. );
  176. }
  177. Widget buildTrackHistoryContentView() {
  178. return Column(
  179. children: [
  180. SizedBox(height: 10.w),
  181. Builder(builder: (context) {
  182. return GestureDetector(
  183. onTap: () {
  184. controller.onTrackStartTimeClick(context);
  185. },
  186. child: Padding(
  187. padding: EdgeInsets.symmetric(vertical: 9.w),
  188. child: Row(
  189. children: [
  190. SizedBox(width: 14.w),
  191. Text(
  192. StringName.trackStartTime,
  193. style: TextStyle(
  194. fontSize: 14.sp,
  195. color: ColorName.black80,
  196. fontWeight: FontWeight.bold),
  197. ),
  198. Spacer(),
  199. Obx(() {
  200. return Text(
  201. controller.trackStartTime?.format('yyyy-MM-dd HH:mm') ??
  202. '',
  203. style:
  204. TextStyle(fontSize: 14.sp, color: ColorName.black50),
  205. );
  206. }),
  207. SizedBox(width: 6.w),
  208. Assets.images.iconTrackSelectTimeArrow
  209. .image(width: 16.w, height: 16.w),
  210. SizedBox(width: 14.w),
  211. ],
  212. ),
  213. ),
  214. );
  215. }),
  216. Builder(builder: (context) {
  217. return GestureDetector(
  218. onTap: () {
  219. controller.onTrackEndTimeClick(context);
  220. },
  221. child: Padding(
  222. padding: EdgeInsets.symmetric(vertical: 9.w),
  223. child: Row(
  224. children: [
  225. SizedBox(width: 14.w),
  226. Text(
  227. StringName.trackEndTime,
  228. style: TextStyle(
  229. fontSize: 14.sp,
  230. color: ColorName.black80,
  231. fontWeight: FontWeight.bold),
  232. ),
  233. Spacer(),
  234. Obx(() {
  235. return Text(
  236. controller.trackEndTime?.format('yyyy-MM-dd HH:mm') ?? '',
  237. style:
  238. TextStyle(fontSize: 14.sp, color: ColorName.black50),
  239. );
  240. }),
  241. SizedBox(width: 6.w),
  242. Assets.images.iconTrackSelectTimeArrow
  243. .image(width: 16.w, height: 16.w),
  244. SizedBox(width: 14.w),
  245. ],
  246. ),
  247. ),
  248. );
  249. }),
  250. SizedBox(height: 12.w),
  251. Obx(() {
  252. return Visibility(
  253. visible: controller.startAddress != null ||
  254. controller.endAddress != null,
  255. child: Container(
  256. padding: EdgeInsets.all(12.w),
  257. margin: EdgeInsets.symmetric(horizontal: 14.w),
  258. width: double.infinity,
  259. decoration: BoxDecoration(
  260. color: '#E5F8F8F8'.color,
  261. borderRadius: BorderRadius.circular(12.w),
  262. ),
  263. child: Column(
  264. children: [
  265. buildAddressInfoView(
  266. '#12C172'.color,
  267. StringName.trackStartLocation,
  268. controller.startAddress ?? ''),
  269. Align(
  270. alignment: Alignment.centerLeft,
  271. child: Container(
  272. margin: EdgeInsets.only(left: 3.5.w),
  273. child: Assets.images.bgTrackLocationTie
  274. .image(width: 1.5.w))),
  275. buildAddressInfoView(
  276. '#F3353A'.color,
  277. StringName.trackEndLocation,
  278. controller.endAddress ?? ''),
  279. ],
  280. )),
  281. );
  282. })
  283. ],
  284. );
  285. }
  286. Widget buildAddressInfoView(Color color, String title, String content) {
  287. return Row(
  288. children: [
  289. Container(
  290. width: 10.w,
  291. height: 10.w,
  292. decoration: BoxDecoration(
  293. shape: BoxShape.circle,
  294. border: Border.all(color: color, width: 2.w),
  295. ),
  296. ),
  297. SizedBox(width: 11.w),
  298. Text(title,
  299. style: TextStyle(
  300. fontSize: 13.sp,
  301. color: ColorName.black80,
  302. fontWeight: FontWeight.bold)),
  303. Expanded(
  304. child: Text(content,
  305. style: TextStyle(fontSize: 13.sp, color: ColorName.black70)),
  306. )
  307. ],
  308. );
  309. }
  310. Widget buildTrackNowContentView() {
  311. return Column(
  312. children: [
  313. SizedBox(height: 20.w),
  314. Row(
  315. children: [
  316. SizedBox(width: 12.w),
  317. Assets.images.iconTrackLocationNow.image(width: 20.w, height: 20.w),
  318. SizedBox(width: 3.w),
  319. Obx(() {
  320. return RelativeTimeText(
  321. startPerchText: '当前位置·',
  322. endPerchText:
  323. controller.currentLocation?.lastUpdateTime == null
  324. ? ''
  325. : '更新',
  326. timestamp: controller.currentLocation?.lastUpdateTime,
  327. updateInterval: Duration(minutes: 1),
  328. style: TextStyle(
  329. fontSize: 15.sp,
  330. color: '#333333'.color,
  331. fontWeight: FontWeight.bold));
  332. })
  333. ],
  334. ),
  335. SizedBox(height: 16.w),
  336. Container(
  337. width: double.infinity,
  338. margin: EdgeInsets.symmetric(horizontal: 12.w),
  339. padding: EdgeInsets.all(14.w),
  340. decoration: BoxDecoration(
  341. color: '#F9F9F9'.color,
  342. borderRadius: BorderRadius.circular(6.w),
  343. ),
  344. child: Obx(() {
  345. return Text(controller.currentLocation?.address ?? '--',
  346. style: TextStyle(fontSize: 14.sp, color: '#666666'.color));
  347. }),
  348. )
  349. ],
  350. );
  351. }
  352. }