home_map_view.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:trackoffical_app/generated/assets.dart';
  4. import 'package:trackoffical_app/model.dart';
  5. import 'package:trackoffical_app/screen.dart';
  6. import 'package:trackoffical_app/service/mock.dart';
  7. import 'package:trackoffical_app/utils.dart';
  8. import 'package:trackoffical_app/view/qr_scan.dart';
  9. import 'package:trackoffical_app/widget/app_dialog.dart';
  10. import '../../widget/app_net_image.dart';
  11. import '../../widget/hard_level.dart';
  12. // import '../activity_list/activity_list_view.dart';
  13. import 'home_controller.dart';
  14. class HomeMapView extends GetView<HomeController> {
  15. const HomeMapView({super.key});
  16. @override
  17. Widget build(BuildContext context) {
  18. return DefaultTabController(
  19. initialIndex: 0,
  20. length: 2,
  21. child: Scaffold(
  22. appBar: _AppBar(),
  23. body: Padding(
  24. padding: const EdgeInsets.all(12),
  25. child: TabBarView(
  26. children: [_TabMapActivity(), _TabDirect()],
  27. )),
  28. ),
  29. );
  30. }
  31. }
  32. class _AppBar extends GetView<HomeController> implements PreferredSizeWidget {
  33. @override
  34. Widget build(BuildContext context) {
  35. var theme = Theme.of(context);
  36. theme = theme.copyWith(
  37. colorScheme: theme.colorScheme.copyWith(
  38. surfaceVariant: Colors.transparent,
  39. ));
  40. return Container(
  41. decoration: BoxDecoration(
  42. gradient: LinearGradient(colors: [
  43. context.theme.colorScheme.secondary,
  44. context.theme.colorScheme.onSecondaryContainer,
  45. ]),
  46. boxShadow: [
  47. BoxShadow(
  48. color: Colors.grey.withOpacity(0.5),
  49. spreadRadius: 3,
  50. blurRadius: 5,
  51. offset: const Offset(0, 2), // changes position of shadow
  52. ),
  53. ],
  54. ),
  55. child: Column(
  56. crossAxisAlignment: CrossAxisAlignment.start,
  57. children: [
  58. SizedBox(
  59. height: MediaQuery.of(context).padding.top,
  60. ),
  61. const Spacer(),
  62. SizedBox(
  63. width: 68.0.wp,
  64. height: 40,
  65. child: Theme(
  66. data: theme,
  67. child: TabBar(
  68. tabs: const [
  69. Tab(text: '地图/活动'),
  70. Tab(text: '直接加入'),
  71. ],
  72. onTap: (i) {
  73. controller.flushGalleryData();
  74. },
  75. labelColor: Colors.white,
  76. unselectedLabelColor: Colors.white,
  77. labelStyle: const TextStyle(
  78. fontSize: 20, fontWeight: FontWeight.w700),
  79. unselectedLabelStyle: const TextStyle(fontSize: 14),
  80. indicatorColor: Colors.white,
  81. ))),
  82. ],
  83. ),
  84. );
  85. }
  86. @override
  87. Size get preferredSize => const Size.fromHeight(kToolbarHeight);
  88. }
  89. class _TabMapActivity extends GetView<HomeController> {
  90. @override
  91. Widget build(BuildContext context) {
  92. return Obx(() {
  93. final data = controller.mapList;
  94. return _dataView(context, data, controller.mapInfoListScrollController);
  95. });
  96. }
  97. }
  98. Widget _dataView(BuildContext context, List<MapInfo> data,
  99. ScrollController scrollController) {
  100. return GridView.builder(
  101. itemCount: data.length,
  102. controller: scrollController,
  103. gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
  104. //设置列数
  105. crossAxisCount: 2,
  106. //设置横向间距
  107. crossAxisSpacing: 10,
  108. //设置主轴间距
  109. mainAxisSpacing: 10,
  110. childAspectRatio: 0.66),
  111. itemBuilder: (context, i) {
  112. return GalleryCardWidget(data: data[i]);
  113. });
  114. }
  115. class GalleryCardWidget extends GetView<HomeController> {
  116. final MapInfo data;
  117. const GalleryCardWidget({super.key, required this.data});
  118. void onTap() async {
  119. var pin = '';
  120. var isCancel = false;
  121. if (data.needPin) {
  122. isCancel = true;
  123. await Get.dialog(AppDialog(
  124. title: const Text('请输入PIN码'),
  125. content: SizedBox(
  126. width: 50.0.wp,
  127. child: TextField(
  128. onChanged: (v) {
  129. pin = v;
  130. },
  131. maxLines: 1,
  132. maxLength: 8,
  133. style: const TextStyle(color: Colors.white),
  134. )),
  135. onCancel: () => Get.back(),
  136. onConfirm: () {
  137. isCancel = false;
  138. Get.back();
  139. },
  140. ));
  141. }
  142. // if (!isCancel) {
  143. // Get.to(() => ActivityListView(
  144. // mapName: data.name,
  145. // mapId: data.id,
  146. // pin: pin,
  147. // isDirectIn: false,
  148. // ));
  149. // }
  150. }
  151. @override
  152. Widget build(BuildContext context) {
  153. return GestureDetector(
  154. onTap: data.isOpen ? onTap : null,
  155. child: Card(
  156. color: const Color(0xfff2faff),
  157. surfaceTintColor: const Color(0xfff2faff),
  158. shape: const RoundedRectangleBorder(
  159. borderRadius: BorderRadius.all(Radius.circular(5.44))),
  160. clipBehavior: Clip.antiAlias,
  161. child: Column(
  162. crossAxisAlignment: CrossAxisAlignment.start,
  163. children: [
  164. AspectRatio(aspectRatio: 1, child: wImage()),
  165. Expanded(
  166. child: Padding(
  167. padding: const EdgeInsets.all(6),
  168. child: Column(
  169. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  170. crossAxisAlignment: CrossAxisAlignment.start,
  171. children: [
  172. Text(
  173. data.name,
  174. style: const TextStyle(
  175. fontSize: 15.24,
  176. fontWeight: FontWeight.w500,
  177. ),
  178. textAlign: TextAlign.start,
  179. maxLines: 1,
  180. overflow: TextOverflow.ellipsis,
  181. ),
  182. Row(
  183. crossAxisAlignment: CrossAxisAlignment.end,
  184. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  185. children: [
  186. Column(
  187. crossAxisAlignment: CrossAxisAlignment.start,
  188. children: [
  189. Row(
  190. crossAxisAlignment: CrossAxisAlignment.center,
  191. children: [
  192. // Image.asset(Assets.imagesIcDistanceStraight, height: 10),
  193. const Icon(
  194. Icons.location_on,
  195. size: 15,
  196. color: Colors.grey,
  197. ),
  198. const SizedBox(width: 6),
  199. getDistanceText(data),
  200. ],
  201. ),
  202. HardLevel(data.level),
  203. ],
  204. ),
  205. data.isRecommend
  206. ? Container(
  207. width: 5.56.wp,
  208. height: 5.56.wp,
  209. decoration: const BoxDecoration(
  210. color: Color(0xffffe8d1),
  211. shape: BoxShape.circle),
  212. alignment: Alignment.center,
  213. child: Text(
  214. '荐',
  215. style: TextStyle(
  216. fontSize: 3.33.wp,
  217. color: const Color(0xffff870d)),
  218. ),
  219. )
  220. : const SizedBox()
  221. ],
  222. )
  223. ],
  224. ))),
  225. ],
  226. ),
  227. ),
  228. );
  229. }
  230. Widget wImage() {
  231. return Stack(
  232. children: [
  233. SizedBox(
  234. height: double.infinity,
  235. child: AppNetImage(netImage: data.image, fit: BoxFit.fitHeight)),
  236. data.isOpen
  237. ? const SizedBox()
  238. : Container(
  239. width: double.infinity,
  240. height: double.infinity,
  241. color: Colors.white.withAlpha(178),
  242. alignment: Alignment.center,
  243. child: const Text(
  244. '待开放',
  245. style: TextStyle(color: Color(0xffff6203), fontSize: 15.24),
  246. ),
  247. )
  248. ],
  249. );
  250. }
  251. Widget getDistanceText(MapInfo data) {
  252. return Obx(() {
  253. final myPosition = controller.myPosition;
  254. var str = '--';
  255. if (myPosition != null) {
  256. final p = data.position;
  257. str = p.distance(myPosition).toString();
  258. }
  259. return Text(str, style: const TextStyle(color: Colors.grey));
  260. });
  261. }
  262. }
  263. class _TabDirect extends GetView<HomeController> {
  264. @override
  265. Widget build(BuildContext context) {
  266. return Column(
  267. children: [
  268. SizedBox(
  269. height: 50.0.wp,
  270. child: Center(
  271. child: _pinInput())),
  272. _divider(),
  273. Expanded(
  274. flex: 100,
  275. child: Center(
  276. child: Column(
  277. mainAxisSize: MainAxisSize.min,
  278. children: [
  279. GestureDetector(
  280. onTap: () async {
  281. final pin = await QRScan.scan();
  282. if (pin != null) {
  283. _submit(pin);
  284. }
  285. },
  286. child: Image.asset(
  287. Assets.imagesIcQrCode,
  288. height: 19.52.wp,
  289. ),
  290. ),
  291. SizedBox(
  292. height: 4.68.wp,
  293. ),
  294. const Text('点击扫码加入')
  295. ],
  296. )),
  297. )
  298. ],
  299. );
  300. }
  301. Widget _pinInput(){
  302. final con = TextEditingController();
  303. return Column(
  304. mainAxisSize: MainAxisSize.min,
  305. crossAxisAlignment: CrossAxisAlignment.start,
  306. children: [
  307. SizedBox(
  308. height: 13.3.wp,
  309. child: Row(
  310. mainAxisSize: MainAxisSize.min,
  311. children: [
  312. SizedBox(
  313. width: 52.0.wp,
  314. child: TextField(
  315. controller: con,
  316. decoration: const InputDecoration(
  317. border: OutlineInputBorder(),
  318. ),
  319. maxLines: 1,
  320. ),
  321. ),
  322. SizedBox(width: 1.39.wp),
  323. SizedBox(
  324. height: double.infinity,
  325. child: FilledButton(
  326. style: FilledButton.styleFrom(
  327. shape: RoundedRectangleBorder(
  328. borderRadius: BorderRadius.circular(1.67.wp)),
  329. ),
  330. onPressed: () {
  331. _submit(con.text);
  332. },
  333. child: Text(
  334. '加入',
  335. style: TextStyle(fontSize: 5.0.wp),
  336. ),
  337. ),
  338. )
  339. ],
  340. ),
  341. ),
  342. SizedBox(height: 1.0.wp),
  343. Text('请输入PIN码加入活动', style: TextStyle(fontSize: 4.4.wp, color: Colors.grey),)
  344. ],
  345. );
  346. }
  347. Widget _divider(){
  348. return SizedBox(width: 76.0.wp, child: Row(
  349. children: [
  350. const Expanded(child: Divider()),
  351. SizedBox(width: 3.0.wp),
  352. const Text('或'),
  353. SizedBox(width: 3.0.wp),
  354. const Expanded(child: Divider()),
  355. ],
  356. )) ;
  357. }
  358. void _submit(String pin) {
  359. tryCatchApi(() async {
  360. // Get.to(() => ActivityListView(
  361. // mapName: '',
  362. // mapId: 0,
  363. // pin: pin,
  364. // isDirectIn: true,
  365. // ));
  366. });
  367. }
  368. }
  369. void main() {
  370. Mock.initServices();
  371. Get.put(HomeController());
  372. runPreview(const HomeMapView());
  373. }