You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

896 lines
31 KiB

import 'dart:ui';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
import 'package:flutter_baidu_mapapi_utils/flutter_baidu_mapapi_utils.dart';
import 'package:flutter_bmflocation/flutter_bmflocation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/main.dart';
import 'package:huixiang/retrofit/data/base_data.dart';
import 'package:huixiang/retrofit/data/store.dart';
import 'package:huixiang/retrofit/retrofit_api.dart';
import 'package:huixiang/union/union_list.dart';
import 'package:huixiang/utils/event_type.dart';
import 'package:huixiang/utils/font_weight.dart';
import 'package:huixiang/utils/location.dart';
import 'package:huixiang/view_widget/border_text.dart';
import 'package:huixiang/view_widget/classic_header.dart';
import 'package:huixiang/view_widget/custom_image.dart';
import 'package:huixiang/view_widget/my_appbar.dart';
import 'package:huixiang/view_widget/my_tab.dart';
import 'package:huixiang/view_widget/request_permission.dart';
import 'package:huixiang/view_widget/round_button.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
import '../utils/flutter_utils.dart';
class UnionPage extends StatefulWidget {
final int initialIndex;
UnionPage(Key key, this.initialIndex) : super(key: key);
@override
State<StatefulWidget> createState() {
return UnionPageState();
}
}
class UnionPageState extends State<UnionPage>
with
AutomaticKeepAliveClientMixin,
WidgetsBindingObserver,
SingleTickerProviderStateMixin {
final RefreshController refreshController =
RefreshController(initialRefresh: false);
final RefreshController refreshController1 =
RefreshController(initialRefresh: false);
final RefreshController refreshController2 =
RefreshController(initialRefresh: false);
final RefreshController refreshController3 =
RefreshController(initialRefresh: false);
ApiService apiService;
bool isKeyBoardShow = false;
BMFCoordinate latLng;
jumpIndex(jpIndex) {
tabController.index = jpIndex;
}
@override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
if (Location.getInstance() != null &&
Location.getInstance().aMapFlutterLocation != null)
Location.getInstance().aMapFlutterLocation.stopLocation();
if (refreshController != null) refreshController.dispose();
if (refreshController1 != null) refreshController1.dispose();
if (refreshController2 != null) refreshController2.dispose();
if (refreshController3 != null) refreshController3.dispose();
}
@override
void didChangeMetrics() {
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
print("object: ${MediaQuery.of(context).viewInsets.bottom}");
if (MediaQuery.of(context).viewInsets.bottom == 0) {
if (isKeyBoardShow) {
isKeyBoardShow = false;
//关闭键盘 软键盘关闭了, 清除输入控件的焦点, 否则重新进入页面会导致软键盘再弹出问题
FocusScope.of(context).requestFocus(FocusNode());
}
} else {
isKeyBoardShow = true;
}
});
});
}
@override
void initState() {
super.initState();
if (tabController == null)
tabController = TabController(
length: 4, vsync: this, initialIndex: widget.initialIndex);
// tabController?.addListener(() {
// startLocation();
// });
WidgetsBinding.instance.addObserver(this);
eventBus.on<EventType>().listen((event) {
if (event.type < 3) {
setState(() {});
}
});
getLatLng();
startLocation(false);
}
RefreshController tabRefresh() {
RefreshController tempRef;
if (tabController.index == 0)
tempRef = refreshController;
else if (tabController.index == 1)
tempRef = refreshController1;
else if (tabController.index == 2)
tempRef = refreshController2;
else if (tabController.index == 3) tempRef = refreshController3;
return tempRef;
}
startLocation(bool isOnRefresh) async {
if (!isOnRefresh) EasyLoading.show(status: S.current.zhengzaijiazai);
Location.getInstance().startLocation(context, (BaiduLocation result) {
if (result != null &&
result.latitude != null &&
result.longitude != null) {
print("location: $result");
latLng = BMFCoordinate(result.latitude, result.longitude);
BMFCalculateUtils.coordConvert(
coordinate: latLng,
fromType: BMF_COORD_TYPE.BD09LL,
toType: BMF_COORD_TYPE.COMMON)
.then((value) {
this.latLng = value;
saveLatLng(
value, result.province, result.city, result.district);
print("union: Location result ${value.latitude} "
"${value.longitude}");
Location.getInstance().stopLocation();
queryStore(
"${value.latitude}",
"${value.longitude}",
result.province,
result.city,
result.district,
"",
-1);
if (_mapController != null)
_mapController.updateMapOptions(BMFMapOptions(
center: value,
zoomLevel: 15,
));
});
} else {
getLatLng();
// EasyLoading.dismiss();
}
}).then((value) {
if (!value) {
EasyLoading.dismiss();
tabRefresh().refreshFailed();
}
});
}
saveLatLng(BMFCoordinate latLng, province, city, district) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("latitude", "${latLng.latitude}");
await prefs.setString("longitude", "${latLng.longitude}");
if (province != null) await prefs.setString("province", province);
if (city != null) await prefs.setString("city", city);
if (district != null) await prefs.setString("district", district);
}
getLatLng() async {
SharedPreferences.getInstance().then(
(value) => {
// apiService = ApiService(Dio(),
// context: context,
// token: value.getString('token'),
// showLoading: false),
if (value.containsKey("latitude") &&
value.containsKey("longitude") &&
value.containsKey("province") &&
value.containsKey("city") &&
value.containsKey("district"))
{
latLng = BMFCoordinate(double.tryParse(value.getString("latitude")),
double.tryParse(value.getString("longitude"))),
queryStore(
value.getString("latitude"),
value.getString("longitude"),
value.getString("province"),
value.getString("city"),
value.getString("district"),
"",
-1),
setState(() {
if (_mapController != null) {
_mapController.updateMapOptions(BMFMapOptions(
center: latLng,
zoomLevel: 15,
));
}
})
}
else
{
queryStore("", "", "", "", "", "", -1),
}
},
);
}
List<Store> storeList;
List<Store> storeList1;
List<Store> storeList2;
List<Store> storeList3;
queryStore(latitude, longitude, province, city, district, searchKey,
int index) async {
if (apiService == null) {
SharedPreferences value = await SharedPreferences.getInstance();
apiService = ApiService(
Dio(),
context: context,
token: value.getString("token"),
);
}
BaseData<List<Store>> baseData = await apiService.queryStore({
// "city": city,
// "district": district,
// "province": province,
"latitude": latitude,
"longitude": longitude,
if(searchKey != "")
"searchKey": searchKey,
"serviceType": (tabController.index == 0 && index == -1) || index == 0
? ""
: ((tabController.index == 1 && index == -1) || index == 1
? "EATSTORE"
: ((tabController.index == 2 && index == -1) || index == 2
? "DRINKSTORE"
: "HAPPYSTORE")),
}).catchError((error) {
if (index == -1) tabRefresh().refreshFailed();
});
if (baseData != null && baseData.isSuccess) {
if (index == -1 && storeList == null) {
if (tabController.index != 0)
queryStore(
latitude, longitude, province, city, district, searchKey, 0);
if (tabController.index != 1)
queryStore(
latitude, longitude, province, city, district, searchKey, 1);
if (tabController.index != 2)
queryStore(
latitude, longitude, province, city, district, searchKey, 2);
if (tabController.index != 3)
queryStore(
latitude, longitude, province, city, district, searchKey, 3);
}
if ((tabController.index == 0 && index == -1) || index == 0)
storeList = baseData.data;
else if ((tabController.index == 1 && index == -1) || index == 1)
storeList1 = baseData.data;
else if ((tabController.index == 2 && index == -1) || index == 2)
storeList2 = baseData.data;
else if ((tabController.index == 3 && index == -1) || index == 3)
storeList3 = baseData.data;
if (index == -1) tabRefresh().refreshCompleted();
} else {
if (index == -1) tabRefresh().refreshFailed();
}
EasyLoading.dismiss();
setState(() {});
}
TabController tabController;
@override
Widget build(BuildContext context) {
super.build(context);
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: MyAppBar(
title: "",
leading: false,
brightness: Brightness.light,
titleChild: PreferredSize(
preferredSize: Size(double.infinity, 38.h),
child: Theme(
data: ThemeData(
splashColor: Colors.transparent, // 点击时的水波纹颜色设置为透明
highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明
),
child: TabBar(
controller: tabController,
isScrollable: true,
//可滚动
indicatorColor: Color(0xff39B54A),
labelColor: Colors.black,
labelStyle: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
unselectedLabelStyle: TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.normal,
),
// controller: tabController,
//未选中文字颜色
unselectedLabelColor: Color(0xffA29E9E),
indicatorSize: TabBarIndicatorSize.label,
//指示器与文字等宽
tabs: <Widget>[
MyTab(text: S.of(context).quanbu),
MyTab(text: ""),
MyTab(text: ""),
MyTab(text: ""),
],
)),
)),
body: TabBarView(
controller: tabController,
children: [
UnionList(refreshController, storeList, () {
startLocation(true);
},(txt){
queryStore("","","","","",txt,0);
}),
UnionList(refreshController1, storeList1, () {
startLocation(true);
},(txt){
queryStore("","","","","",txt,0);
}),
UnionList(refreshController2, storeList2, () {
startLocation(true);
},(txt){
queryStore("","","","","",txt,0);
}),
UnionList(refreshController3, storeList3, () {
startLocation(true);
},(txt){
queryStore("","","","","",txt,0);
}),
],
),
));
// GestureDetector(
// onTap: () {
// FocusScope.of(context).requestFocus(FocusNode());
// },
// child: Scaffold(
// backgroundColor: Colors.white,
// resizeToAvoidBottomInset: false,
// appBar: MyAppBar(
// // titleChild: buildSearchItem(),
// title: "",
// leading: false,
// background: Colors.white,
// brightness: Brightness.light,
// ),
// body: Column(
// children: [
// // Row(
// // mainAxisAlignment: MainAxisAlignment.start,
// // crossAxisAlignment: CrossAxisAlignment.end,
// // children: [
// // Expanded(child:PreferredSize(
// // preferredSize: Size(double.infinity, 52.h),
// // child: Container(
// // padding: EdgeInsets.only(top:15.h),
// // color: Color(0xFFFAFAFA),
// // child: ItemTitle(
// // text: S.of(context).jingbilianmenghuiyuandian,
// // imgPath: "assets/image/icon_union_store.webp",
// // ),
// // ),
// // )),
// // GestureDetector(
// // onTap: (){
// // setState(() {
// // var storeName = storeList.firstWhere((x)=>x.storeName == "一心回乡商城");
// // if(storeName == null)
// // return;
// // Navigator.of(context).pushNamed(
// // '/router/shopping_mall_home',
// // arguments: {
// // "type":0,
// // "id":storeName.id,
// // "tenant": storeName.tenantCode,
// // "storeName":storeName.storeName
// // },
// // );
// // });
// // },
// // child:Container(
// // margin: EdgeInsets.only(right: 18),
// // height: 25.h,
// // width: 102.w,
// // color: Colors.white,
// // child:Row(
// // mainAxisAlignment: MainAxisAlignment.center,
// // crossAxisAlignment: CrossAxisAlignment.center,
// // children: [
// // Text(
// // "一心回乡商城",
// // style: TextStyle(
// // fontSize: 12.sp,
// // fontWeight: MyFontWeight.regular,
// // color: Colors.black,
// // ),
// // ),
// // Icon(
// // Icons.keyboard_arrow_right,
// // size: 16,
// // ),
// // ],
// // ),
// // ),
// // ),
// // ],
// // ),
// buildItem()
// ],
// ),
// ),
// );
}
Widget buildItem(
RefreshController refreshController,
) {
return Column(
children: [
// buildSearchItem(),
Container(
height: MediaQuery.of(context).size.height -
103.h -
MediaQuery.of(context).padding.top,
child: SmartRefresher(
controller: refreshController,
enablePullUp: false,
enablePullDown: true,
physics: BouncingScrollPhysics(),
header: MyHeader(),
onRefresh: () {
startLocation(false);
},
child: ListView.builder(
itemCount: storeList == null ? 0 : storeList.length,
padding: EdgeInsets.only(
top: 8.h,
bottom: 84.h, /* + (375.h - 88.h) + 4.h*/
),
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) {
return InkWell(
onTap: () {
if (storeList[position].posType.code == "NORMALSTORE") {
showDeleteDialog();
} else if (storeList[position].posType.code ==
"RETAILSTORE" &&
storeList[position].storeName == "一心回乡商城") {
Navigator.of(context).pushNamed(
'/router/shopping_mall_home',
arguments: {
"type": 0,
"id": storeList[position].id,
"tenant": storeList[position].tenantCode,
"storeName": storeList[position].storeName
},
);
} else {
Navigator.of(context).pushNamed(
'/router/store_order',
arguments: {
"id": storeList[position].id,
"tenant": storeList[position].tenantCode,
"storeName": storeList[position].storeName
},
);
}
},
child: buildStoreItem(storeList[position], position),
);
})),
)
],
);
}
BMFMapController _mapController;
void onMapCreated(BMFMapController controller) {
_mapController = controller;
}
// Widget buildSearchItem() {
// return Container(
// height: 36.h,
// margin: EdgeInsets.fromLTRB(6.w, 0, 14.w, 0),
// padding: EdgeInsets.fromLTRB(0, 6.h, 0, 6.h),
// decoration: BoxDecoration(
// color: Color(0xFFF5FAF7),
// borderRadius: BorderRadius.circular(4),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withAlpha(12),
// offset: Offset(0, 3),
// blurRadius: 14,
// spreadRadius: 0,
// ),
// ],
// ),
// child: TextField(
// textInputAction: TextInputAction.search,
// onEditingComplete: () {
// startLocation(false);
// },
// controller: editingController,
// cursorHeight: 30.h,
// decoration: InputDecoration(
// contentPadding: EdgeInsets.symmetric(
// vertical: 12.h,
// ),
// prefixIcon: Icon(
// Icons.search,
// size: 24,
// color: Colors.black,
// ),
// suffixIcon: InkWell(
// onTap: () {
// editingController.clear();
// },
// child: Icon(
// Icons.close,
// size: 19,
// color: Colors.grey,
// ),
// ),
// border: InputBorder.none,
// ),
// ),
// );
// }
// Widget buildSliverAppBar(BMFMapWidget map) {
// return SliverAppBar(
// // 滑上去时搜索隐藏
// // floating: true,
// // snap: true,
// pinned: true,
// backgroundColor: Color(0xFFFAFAFA),
// elevation: 0,
// automaticallyImplyLeading: false,
// title: Container(
// height: 36.h,
// margin: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0),
// padding: EdgeInsets.fromLTRB(0, 6.h, 0, 6.h),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.all(Radius.circular(4)),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withAlpha(12),
// offset: Offset(0, 3),
// blurRadius: 14,
// spreadRadius: 0,
// )
// ]),
// child: TextField(
// textInputAction: TextInputAction.search,
// onEditingComplete: () {
// startLocation();
// },
// controller: editingController,
// cursorHeight: 30.h,
// decoration: InputDecoration(
// contentPadding: EdgeInsets.symmetric(vertical: 12.h),
// prefixIcon: Icon(
// Icons.search,
// size: 24,
// color: Colors.black,
// ),
// suffixIcon: InkWell(
// onTap: () {
// editingController.clear();
// },
// child: Icon(
// Icons.close,
// size: 19,
// color: Colors.grey,
// ),
// ),
// border: InputBorder.none,
// ),
// ),
// ),
// flexibleSpace: FlexibleSpaceBar(
// background: Container(
// child: map,
// ),
// ),
// expandedHeight: 375.h,
// bottom: PreferredSize(
// preferredSize: Size(double.infinity, 52.h),
// child: Container(
// padding: EdgeInsets.only(top: 6.h),
// color: Color(0xFFFAFAFA),
// child: ItemTitle(
// text: S.of(context).jingbilianmenghuiyuandian,
// imgPath: "assets/image/icon_union_store.webp",
// ),
// ),
// ),
// );
// }
Widget buildStoreItem(Store store, position) {
return Container(
margin: EdgeInsets.fromLTRB(16.w, 8.h, 16.w, 8.h),
// padding: EdgeInsets.fromLTRB(20.w, 20.h, 20.w, 20.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(8)),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(25),
offset: Offset(0, 1),
blurRadius: 12,
spreadRadius: 0,
)
]),
width: double.infinity,
height: 228.h,
child: Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: ClipRRect(
child: MImage(
store.facade,
width: double.infinity,
height: 140.h,
fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp",
),
borderRadius: BorderRadius.vertical(
top: Radius.circular(4),
),
),
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(),
),
Positioned(
bottom: 16.h,
left: 12.w,
right: 0,
child: Container(
height: 100.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MImage(
store.logo,
width: 57,
height: 57,
fit: BoxFit.cover,
isCircle: true,
errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp",
),
SizedBox(
width: 6.w,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 40.h,
),
Text(
store.storeName,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Color(0xFF0D0D0D),
fontSize: 14.sp,
fontWeight: MyFontWeight.bold,
),
),
SizedBox(
height: 5.h,
),
Text(
"${S.of(context).dizhi}:${store.address}",
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Color(0xFF4D4D4D),
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
),
],
)),
Container(
width: 59.w,
height: 18.h,
alignment: Alignment.center,
margin: EdgeInsets.only(top: 20.h),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xFF32A060),
),
child: Visibility(
child: Text(
(store.distance ?? 0) > 1000
? S.of(context).gongli(
((store.distance ?? 0) / 1000 * 100).toInt() /
100.0)
: S.of(context).mi(
((store.distance ?? 0) * 100).toInt() / 100.0),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 10.sp,
),
),
visible: store.distance != null,
),
),
],
),
),
),
],
),
);
}
///扫码提示弹窗
showDeleteDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Container(
width: MediaQuery.of(context).size.width - 84.w,
height: 130.h,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"您即将进行扫码点餐",
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(
height: 30.h,
),
Row(
children: [
Expanded(
child: InkWell(
child: BorderText(
text: "取消",
textColor: Color(0xFF32A060),
fontSize: 16.sp,
fontWeight: FontWeight.bold,
borderColor: Color(0xFF32A060),
radius: 4,
padding: EdgeInsets.all(12),
borderWidth: 1,
),
onTap: () {
Navigator.of(context).pop();
},
),
flex: 1,
),
SizedBox(
width: 16.w,
),
Expanded(
child: InkWell(
child: RoundButton(
text: "确定",
textColor: Colors.white,
radius: 4,
padding: EdgeInsets.all(12),
backgroup: Color(0xFF32A060),
fontSize: 16.sp,
fontWeight: FontWeight.bold,
),
onTap: () {
toScan();
Navigator.of(context).pop();
},
),
flex: 1,
),
],
)
],
),
),
);
},
);
}
///扫码
toScan() async {
if (await Permission.camera.isPermanentlyDenied) {
showCupertinoDialog(
context: context,
builder: (context) {
return RequestPermission(
"assets/image/icon_camera_permission_tips.webp",
S.of(context).ninxiangjiquanxianweikaiqi,
S.of(context).weilekaipaizhaoxuanzhetouxiang,
S.of(context).kaiqiquanxian,
(result) async {
if (result) {
await openAppSettings();
}
},
heightRatioWithWidth: 0.82,
);
});
} else if (await Permission.camera.isGranted) {
// http://pos.app.gznl.top/placeorder/?tableId=1315903669597634560&tenantCode=1166&shopId=1300372027722432512
var result = await Navigator.of(context).pushNamed('/router/qr_scan');
// String result = await scanner.scan();
Uri uri = Uri.parse(result);
String tableId = uri.queryParameters["tableId"];
String tenantCode = uri.queryParameters["tenantCode"];
String shopId = uri.queryParameters["shopId"];
if (tableId != null &&
tableId != "" &&
tenantCode != null &&
tenantCode != "" &&
shopId != null &&
shopId != "") {
Navigator.of(context).pushNamed(
'/router/store_order',
arguments: {
"id": shopId,
"tenant": tenantCode,
"storeName": "",
"tableId": int.tryParse(tableId),
},
);
}
} else {
await Permission.camera.request();
}
}
@override
bool get wantKeepAlive => true;
}