news_home_page.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. import 'dart:async';
  2. import 'package:amap_location_flutter_plugin/amap_location_flutter_plugin.dart';
  3. import 'package:amap_location_flutter_plugin/amap_location_option.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:liftmanager/common/common.dart';
  6. import 'package:liftmanager/internal/news/news_router.dart';
  7. import 'package:liftmanager/internal/news/model/news_comm_entity.dart';
  8. import 'package:liftmanager/internal/news/presenter/news_home_presenter.dart';
  9. import 'package:liftmanager/internal/search/presenter/base_list_provider.dart';
  10. import 'package:liftmanager/internal/work/model/banner_entity.dart';
  11. import 'package:liftmanager/internal/work/work_router.dart';
  12. import 'package:liftmanager/mvp/base_page_state.dart';
  13. import 'package:liftmanager/net/api_service.dart';
  14. import 'package:liftmanager/res/resources.dart';
  15. import 'package:liftmanager/routers/fluro_navigator.dart';
  16. import 'package:liftmanager/utils/theme_utils.dart';
  17. import 'package:liftmanager/utils/toast.dart';
  18. import 'package:liftmanager/widgets/app_city_search_bar.dart';
  19. import 'package:liftmanager/widgets/load_image.dart';
  20. import 'package:liftmanager/widgets/my_refresh_list.dart';
  21. import 'package:liftmanager/widgets/state_layout.dart';
  22. import 'package:permission_handler/permission_handler.dart';
  23. import 'package:provider/provider.dart' as p;
  24. import 'package:flustars/flustars.dart' as FlutterStars;
  25. class NewsPage extends StatefulWidget {
  26. @override
  27. NewsPageState createState() => NewsPageState();
  28. }
  29. const timeout = const Duration(seconds: 5);
  30. class NewsPageState extends BasePageState<NewsPage, NewsHomePresenter>
  31. with TickerProviderStateMixin, AutomaticKeepAliveClientMixin{
  32. Map<String, Object> _locationResult;
  33. StreamSubscription<Map<String, Object>> _locationListener;
  34. AmapLocationFlutterPlugin _locationPlugin = new AmapLocationFlutterPlugin();
  35. BaseListProvider<NewsItem> provider = BaseListProvider<NewsItem>();
  36. TabController _tabController;
  37. PageController _pageController = PageController();
  38. int _index = 0;
  39. Timer _timer;
  40. int _page = 1;
  41. List<BannerEntity> bannerList = [];
  42. List<String> menuTitle = ["互动问答", "电梯保险", "知识学堂"];
  43. List<String> menuImage = ["icon_tdgl", "icon_tdmp", "icon_tdmp"];
  44. List<String> menuDesc = ["1548人发起最新求助", "最高赔付200万", "海量知识任你学"];
  45. String cityName = "";
  46. @override
  47. void initState() {
  48. print("initState");
  49. _locationListener = _locationPlugin
  50. .onLocationChanged()
  51. .listen((Map<String, Object> result) {
  52. setState(() {
  53. _locationPlugin.stopLocation();
  54. _locationResult = result;
  55. // address latitude longitude
  56. _locationResult.forEach((key, value) {
  57. if(key == 'city'){
  58. cityName = '$value';
  59. setState(() {
  60. });
  61. }
  62. print(111);
  63. print('key:$key :');
  64. print('value:$value :');
  65. });
  66. });
  67. });
  68. /// 默认为加载中状态,本页面场景默认为空
  69. provider.setStateTypeNotNotify(StateType.loading);
  70. _tabController = TabController(length: 0, vsync: this);
  71. _timer = Timer.periodic(timeout, _handleTimeout);
  72. super.initState();
  73. // cityName = SpUtil.getString("cityName");
  74. _onRefresh();
  75. getBanner();
  76. getUserInfo();
  77. getLocation();
  78. }
  79. void _setLocationOption() {
  80. if (null != _locationPlugin) {
  81. AMapLocationOption locationOption = new AMapLocationOption();
  82. ///是否单次定位
  83. locationOption.onceLocation = true;
  84. ///是否需要返回逆地理信息
  85. locationOption.needAddress = true;
  86. ///逆地理信息的语言类型
  87. locationOption.geoLanguage = GeoLanguage.DEFAULT;
  88. ///设置Android端连续定位的定位间隔
  89. locationOption.locationInterval = 20000;
  90. ///设置Android端的定位模式<br>
  91. ///可选值:<br>
  92. ///<li>[AMapLocationMode.Battery_Saving]</li>
  93. ///<li>[AMapLocationMode.Device_Sensors]</li>
  94. ///<li>[AMapLocationMode.Hight_Accuracy]</li>
  95. locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
  96. ///设置iOS端的定位最小更新距离<br>
  97. locationOption.distanceFilter = -1;
  98. ///设置iOS端期望的定位精度
  99. /// 可选值:<br>
  100. /// <li>[DesiredAccuracy.Best] 最高精度</li>
  101. /// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
  102. /// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
  103. /// <li>[DesiredAccuracy.Kilometer] 1000米</li>
  104. /// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
  105. locationOption.desiredAccuracy = DesiredAccuracy.NearestTenMeters;
  106. ///设置iOS端是否允许系统暂停定位
  107. locationOption.pausesLocationUpdatesAutomatically = false;
  108. ///将定位参数设置给定位插件
  109. _locationPlugin.setLocationOption(locationOption);
  110. }
  111. }
  112. ///获取定位权限
  113. Future<bool> requestPermission() async {
  114. final permissions = await PermissionHandler()
  115. .requestPermissions([PermissionGroup.location]);
  116. if (permissions[PermissionGroup.location] == PermissionStatus.granted) {
  117. return true;
  118. } else {
  119. toasts('需要定位权限!');
  120. return false;
  121. }
  122. }
  123. ///获取用户信息
  124. void getUserInfo() {
  125. ApiService(context: context).userInfo(
  126. onSuccess: (data) {
  127. if (!mounted) {
  128. return;
  129. }
  130. if(data != null){
  131. FlutterStars.SpUtil.putString(Constant.companyRole,data.roleCode);
  132. }
  133. },
  134. onError: (code, msg) {
  135. });
  136. }
  137. ///获取位置信息
  138. getLocation() async {
  139. if (await requestPermission()) {
  140. if (null != _locationPlugin) {
  141. ///开始定位之前设置定位参数
  142. _setLocationOption();
  143. _locationPlugin.startLocation();
  144. }
  145. }
  146. }
  147. void getBanner() {
  148. ApiService(context: context).getBanner(
  149. onSuccess: (data) {
  150. bannerList = data;
  151. if (bannerList.length > 0) {
  152. _pageController.jumpToPage(0);
  153. _tabController =
  154. TabController(length: bannerList.length, vsync: this);
  155. setState(() {});
  156. }
  157. },
  158. onError: (code, msg) {
  159. showToast(msg);
  160. });
  161. }
  162. _handleTimeout(Timer timer) {
  163. _index++;
  164. _pageController.animateToPage(
  165. _index % (bannerList.length == 0 ? 1 : bannerList.length),
  166. duration: Duration(milliseconds: 16),
  167. curve: Curves.fastOutSlowIn,
  168. );
  169. }
  170. void _onPageChanged(int index) {
  171. _index = index;
  172. _tabController.animateTo(index);
  173. }
  174. @override
  175. void dispose() {
  176. _tabController?.dispose();
  177. _timer.cancel();
  178. _pageController.dispose();
  179. ///移除定位监听
  180. if (null != _locationListener) {
  181. _locationListener.cancel();
  182. }
  183. ///销毁定位
  184. if (null != _locationPlugin) {
  185. _locationPlugin.destroy();
  186. }
  187. super.dispose();
  188. }
  189. @override
  190. Widget build(BuildContext context) {
  191. bool isDark = ThemeUtils.isDark(context);
  192. return p.ChangeNotifierProvider<BaseListProvider<NewsItem>>(
  193. create: (_) => provider,
  194. child: Scaffold(
  195. appBar: AppCitySearchAppBar(
  196. city: "$cityName",
  197. ),
  198. body: Container(
  199. color: ThemeUtils.getBackgroundColor(context),
  200. child: Column(
  201. crossAxisAlignment: CrossAxisAlignment.start,
  202. children: <Widget>[
  203. Offstage(
  204. offstage: bannerList.length == 0,
  205. child: bannerWidget(),
  206. ),
  207. // Container(
  208. //// color: Colors.white,
  209. //// child: _ToolsItem(menuTitle, menuImage, menuDesc, (index) {
  210. //// if (index == 0) {
  211. ////// NavigatorUtils.push(context, AccountRouter.certificatePage);
  212. //// } else if (index == 1) {
  213. ////// NavigatorUtils.push(context, TeamRouter.teamUserPage);
  214. //// }
  215. //// }),
  216. //// ),
  217. Gaps.vGap10,
  218. Container(
  219. height: 45,
  220. padding: EdgeInsets.only(left: 15, right: 15),
  221. alignment: Alignment.centerLeft,
  222. decoration: BoxDecoration(
  223. color: isDark?Colours.dark_bg_color:Colors.white,
  224. border: Border(
  225. bottom: BorderSide(width: 0.5, color: Colours.line),
  226. ),
  227. ),
  228. child: Row(
  229. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  230. children: <Widget>[
  231. Container(
  232. padding: EdgeInsets.only(left: 10),
  233. decoration: BoxDecoration(
  234. border: Border(
  235. left: BorderSide(width: 3, color: Colours.app_main),
  236. )),
  237. child: Text(
  238. "热门新闻",
  239. style: TextStyles.textBold15,
  240. ),
  241. ),
  242. GestureDetector(
  243. onTap: () {
  244. NavigatorUtils.push(
  245. context, NewsRouter.newsTopList);
  246. },
  247. child: Text(
  248. "更多",
  249. style: TextStyle(
  250. fontSize: 13, color: Color(0xFF666666)),
  251. )),
  252. ],
  253. ),
  254. ),
  255. Expanded(
  256. flex: 1,
  257. child: p.Consumer<BaseListProvider<NewsItem>>(
  258. builder: (_, provider, __) {
  259. return MyListView(
  260. itemCount: provider.list.length,
  261. stateType: provider.stateType,
  262. onRefresh: _onRefresh,
  263. loadMore: _loadMore,
  264. // itemExtent: 67.0,
  265. hasMore: provider.hasMore,
  266. itemBuilder: (_, index) {
  267. var item = provider.list[index];
  268. return InkWell(
  269. onTap: () {
  270. NavigatorUtils.push(context,
  271. "${NewsRouter.newsDetail}?id=${item.id}");
  272. },
  273. child: Container(
  274. decoration: BoxDecoration(
  275. color: isDark?Colours.dark_bg_color:Colors.white,
  276. border: Border(
  277. bottom: BorderSide(
  278. width: 0.5, color: Colours.line)),
  279. ),
  280. padding: const EdgeInsets.all(15),
  281. child: Column(
  282. crossAxisAlignment: CrossAxisAlignment.start,
  283. mainAxisAlignment: MainAxisAlignment.start,
  284. children: <Widget>[
  285. Text(
  286. "${item.title}",
  287. style: TextStyle(fontSize: 15,color: isDark?Colours.dark_text:Colours.text),
  288. // overflow: TextOverflow.ellipsis,
  289. ),
  290. Gaps.vGap12,
  291. Text(
  292. "${item.releaseUser}·阅读${item.lookNum}次·点赞${item.likeNum}",
  293. style: TextStyle(
  294. fontSize: 11, color: Colours.text_gray),
  295. )
  296. ],
  297. ),
  298. ),
  299. );
  300. },
  301. );
  302. }))
  303. ],
  304. ),
  305. ),
  306. ));
  307. }
  308. Widget bannerWidget() {
  309. return Container(
  310. height: 160,
  311. child: Stack(
  312. children: <Widget>[
  313. PageView(
  314. children: bannerList.map((item) {
  315. return GestureDetector(
  316. onTap: (){
  317. if(item.url.length>0){
  318. NavigatorUtils.push(context, "${WorkRouter.webview}?title="+Uri.encodeComponent("详情")+"&url="+Uri.encodeComponent(item.url));
  319. }
  320. },
  321. child: Image.network(
  322. item.image,
  323. fit: BoxFit.fill, //使照片占满整个屏幕
  324. ),
  325. );
  326. }).toList(),
  327. onPageChanged: _onPageChanged,
  328. controller: _pageController,
  329. ),
  330. Align(
  331. alignment: Alignment(0.0, 0.9),
  332. child: TabPageSelector(
  333. color: Colors.white,
  334. selectedColor: Colours.app_main,
  335. controller: _tabController,
  336. ),
  337. ),
  338. ],
  339. ));
  340. }
  341. Widget lineTxt(title, value) {
  342. return Container(
  343. padding: EdgeInsets.only(left: 12, top: 5, right: 12),
  344. child: Row(
  345. children: <Widget>[
  346. Text("${title}",
  347. style: TextStyle(fontSize: 13, color: Colours.dark_text_gray)),
  348. Expanded(
  349. flex: 1,
  350. child: Text(
  351. "${value}",
  352. textAlign: TextAlign.right,
  353. style: TextStyle(fontSize: 13, color: Colours.dark_text_gray),
  354. ),
  355. )
  356. ],
  357. ),
  358. );
  359. }
  360. Future _onRefresh() async {
  361. _page = 1;
  362. await presenter.newsList(context, _page, 1, "", cityName);
  363. }
  364. Future _loadMore() async {
  365. _page++;
  366. await presenter.newsList(context, _page, 1, "", cityName);
  367. }
  368. @override
  369. NewsHomePresenter createPresenter() {
  370. return NewsHomePresenter();
  371. }
  372. @override
  373. bool get wantKeepAlive => true;
  374. }
  375. class _ToolsItem extends StatelessWidget {
  376. _ToolsItem(this.titles, this.imgs, this.desc, this.onTap, {Key key})
  377. : super(key: key);
  378. List<String> titles;
  379. List<String> imgs;
  380. List<String> desc;
  381. Function onTap;
  382. @override
  383. Widget build(BuildContext context) {
  384. return GridView.builder(
  385. shrinkWrap: true,
  386. padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 0),
  387. physics: NeverScrollableScrollPhysics(),
  388. gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
  389. crossAxisCount: 3, childAspectRatio: 0.9, crossAxisSpacing: 2),
  390. itemCount: titles.length,
  391. itemBuilder: (_, index) {
  392. return InkWell(
  393. child: Column(
  394. mainAxisAlignment: MainAxisAlignment.center,
  395. children: <Widget>[
  396. LoadAssetImage(
  397. "work/${imgs[index]}",
  398. width: 45.0,
  399. height: 45,
  400. ),
  401. Gaps.vGap10,
  402. Text(
  403. titles[index],
  404. style: TextStyles.textSize14,
  405. ),
  406. Gaps.vGap10,
  407. Text(
  408. desc[index],
  409. style: TextStyles.textGray10,
  410. )
  411. ],
  412. ),
  413. onTap: () {
  414. onTap(index);
  415. });
  416. },
  417. );
  418. }
  419. }