# Conflicts: # pubspec.yamltags/0.0.1
@@ -249,9 +249,9 @@ | |||||
}, | }, | ||||
{ | { | ||||
"name": "intl", | "name": "intl", | ||||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/intl-0.16.1", | |||||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/intl-0.15.7", | |||||
"packageUri": "lib/", | "packageUri": "lib/", | ||||
"languageVersion": "2.5" | |||||
"languageVersion": "2.0" | |||||
}, | }, | ||||
{ | { | ||||
"name": "jdsdk", | "name": "jdsdk", | ||||
@@ -475,6 +475,12 @@ | |||||
"packageUri": "lib/", | "packageUri": "lib/", | ||||
"languageVersion": "2.0" | "languageVersion": "2.0" | ||||
}, | }, | ||||
{ | |||||
"name": "string_validator", | |||||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/string_validator-0.1.4", | |||||
"packageUri": "lib/", | |||||
"languageVersion": "2.0" | |||||
}, | |||||
{ | { | ||||
"name": "synchronized", | "name": "synchronized", | ||||
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/synchronized-2.2.0", | "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/synchronized-2.2.0", | ||||
@@ -596,7 +602,7 @@ | |||||
"languageVersion": "2.1" | "languageVersion": "2.1" | ||||
} | } | ||||
], | ], | ||||
"generated": "2020-09-29T08:01:12.048733Z", | |||||
"generated": "2020-09-29T09:19:18.536482Z", | |||||
"generator": "pub", | "generator": "pub", | ||||
"generatorVersion": "2.7.2" | "generatorVersion": "2.7.2" | ||||
} | } |
@@ -0,0 +1,115 @@ | |||||
import 'dart:async'; | |||||
import 'dart:convert'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter/services.dart'; | |||||
import 'package:zhiying_base_widget/dialog/global_dialog/intellect_search_goods_dialog/model/Intellect_search_set_model.dart'; | |||||
import 'package:zhiying_base_widget/utils/contants.dart'; | |||||
import 'package:zhiying_comm/util/shared_prefe_util.dart'; | |||||
import 'intellect_search_goods_dialog.dart'; | |||||
import 'intellect_search_no_goods_dialog.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:string_validator/string_validator.dart'; | |||||
class IntellectCreate { | |||||
static IntellectSearchSetModel _setModel; | |||||
///判断规则 | |||||
static checkAndCreate(AppLifecycleState state, BuildContext context) async { | |||||
if (state == AppLifecycleState.resumed && | |||||
!Constants.isShowIntellectDialog) { | |||||
_requestSetData(context); | |||||
} | |||||
} | |||||
///请求设置参数 | |||||
static _requestSetData(BuildContext context) async { | |||||
if (_setModel == null) { | |||||
var param = {"webId": ""}; | |||||
//请求参数 | |||||
NetUtil.request('/api/v1/cfg/app_clipboard', params: param, | |||||
onSuccess: (data) async { | |||||
print("设置参数" + data.toString()); | |||||
///检查是否已缓存过设置信息 | |||||
String result = await SharedPreferencesUtil.getStringValue( | |||||
Constants.spIsCacheSetModel); | |||||
_setModel = IntellectSearchSetModel.fromJson(data); | |||||
if (result.isEmpty) { | |||||
validate(context, _setModel); | |||||
} | |||||
SharedPreferencesUtil.setNetCacheResult( | |||||
Constants.spIsCacheSetModel, json.encode(data)); | |||||
}); | |||||
///拿缓存数据 | |||||
var cacheData = await SharedPreferencesUtil.getNetCacheResult( | |||||
Constants.spIsCacheSetModel); | |||||
///如果存在缓存直接进入验证阶段 | |||||
if (cacheData.isNotEmpty) { | |||||
_setModel = IntellectSearchSetModel.fromJson(cacheData); | |||||
validate(context, _setModel); | |||||
} | |||||
} else { | |||||
validate(context, _setModel); | |||||
} | |||||
} | |||||
static checkAndCreateFirst(BuildContext context) async { | |||||
///检查规则 | |||||
IntellectCreate.checkAndCreate(AppLifecycleState.resumed, context); | |||||
} | |||||
///请求数据打开弹窗 | |||||
static requestDialog(BuildContext context, String content) async { | |||||
Constants.isShowIntellectDialog = true; | |||||
await showDialog(context: context, child: IntellectSearchGoodsDialog()); | |||||
Constants.isShowIntellectDialog = false; | |||||
} | |||||
///检查字段是否被监听 | |||||
static void validate( | |||||
BuildContext context, IntellectSearchSetModel setModel) async { | |||||
ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); | |||||
String content = data.text; | |||||
//是否监听 | |||||
if (setModel.state != "1") { | |||||
return; | |||||
} | |||||
///长度大小限制 | |||||
if (setModel.keywordLimitState == "1" && | |||||
(int.tryParse(setModel.keywordLimitMin) < content.length) || | |||||
(int.tryParse(setModel.keywordLimitMax) > content.length)) { | |||||
return; | |||||
} | |||||
//是否纯数字 | |||||
if (setModel.keywordNum == "1" && isNumeric(content)) { | |||||
return; | |||||
} | |||||
///是否纯字母 | |||||
if (setModel.keywordAlpha == "1" && isAlpha(content)) { | |||||
return; | |||||
} | |||||
///是否仅包含数字和字母 | |||||
if (setModel.keywordAlphanum == "1" && isAlphanumeric(content)) { | |||||
return; | |||||
} | |||||
///是否包含某个排除词 | |||||
if (setModel.exclude.length > 0) { | |||||
for (var item in setModel.exclude) { | |||||
if (contains(content, item)) { | |||||
return; | |||||
} | |||||
} | |||||
} | |||||
requestDialog(context, content); | |||||
} | |||||
} |
@@ -0,0 +1,246 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class IntellectSearchGoodsDialog extends StatefulWidget { | |||||
@override | |||||
_IntellectSearchGoodsDialogState createState() => | |||||
_IntellectSearchGoodsDialogState(); | |||||
} | |||||
class _IntellectSearchGoodsDialogState | |||||
extends State<IntellectSearchGoodsDialog> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.transparent, | |||||
body: InkWell( | |||||
onTap: () { | |||||
Navigator.of(context).pop(); | |||||
}, | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
GestureDetector( | |||||
onTap: () {}, | |||||
child: Stack( | |||||
children: <Widget>[ | |||||
Container( | |||||
margin: EdgeInsets.only(top: 38.h, left: 92.w, right: 92.w), | |||||
padding: EdgeInsets.only( | |||||
top: (38 + 38).h, | |||||
left: 30.w, | |||||
right: 30.w, | |||||
bottom: 48.h), | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
borderRadius: BorderRadius.circular(16)), | |||||
width: double.infinity, | |||||
child: Column( | |||||
children: <Widget>[_bulidTopItem(), _buildBottomItem()], | |||||
), | |||||
), | |||||
Container( | |||||
height: 76.h, | |||||
child: Center( | |||||
child: Container( | |||||
color: Colors.red, | |||||
height: 76.h, | |||||
width: 216.w, | |||||
child: CachedNetworkImage( | |||||
imageUrl: "", | |||||
), | |||||
)), | |||||
), | |||||
], | |||||
), | |||||
) | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
_bulidTopItem() { | |||||
return Row( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
Container( | |||||
color: Colors.red, | |||||
width: 160.w, | |||||
height: 160.w, | |||||
), | |||||
SizedBox( | |||||
width: 19.w, | |||||
), | |||||
Expanded( | |||||
child: Container( | |||||
child: Column( | |||||
mainAxisSize: MainAxisSize.max, | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
Column( | |||||
children: <Widget>[ | |||||
Text( | |||||
"2020新款春款波点连衣裙新短发dfasdfas短发时代发发呆发顺丰的打算萨阿啊", | |||||
maxLines: 2, | |||||
overflow: TextOverflow.ellipsis, | |||||
style: TextStyle(color: Colors.black, fontSize: 24.sp), | |||||
), | |||||
SizedBox( | |||||
height: 5.h, | |||||
), | |||||
Row( | |||||
children: <Widget>[ | |||||
Container( | |||||
decoration: BoxDecoration( | |||||
color: Colors.red, | |||||
borderRadius: BorderRadius.circular(2)), | |||||
padding: EdgeInsets.all(2), | |||||
child: Row( | |||||
mainAxisSize: MainAxisSize.min, | |||||
children: <Widget>[ | |||||
Container( | |||||
width: 30.w, | |||||
height: 30.w, | |||||
decoration: BoxDecoration(color: Colors.white), | |||||
child: Center( | |||||
child: Text( | |||||
"券", | |||||
style: TextStyle( | |||||
color: Colors.red, fontSize: 20.sp), | |||||
), | |||||
), | |||||
), | |||||
Padding( | |||||
padding: const EdgeInsets.only(left: 4, right: 4), | |||||
child: Text( | |||||
"¥100", | |||||
style: TextStyle( | |||||
color: Colors.white, fontSize: 20.sp), | |||||
), | |||||
) | |||||
], | |||||
), | |||||
), | |||||
SizedBox( | |||||
width: 12.w, | |||||
), | |||||
Container( | |||||
decoration: BoxDecoration( | |||||
color: HexColor.fromHex("#FFFFF6C1"), | |||||
borderRadius: BorderRadius.circular(2)), | |||||
padding: EdgeInsets.all(2), | |||||
child: Row( | |||||
mainAxisSize: MainAxisSize.min, | |||||
children: <Widget>[ | |||||
SizedBox( | |||||
height: 30.w, | |||||
), | |||||
Center( | |||||
child: Padding( | |||||
padding: | |||||
const EdgeInsets.only(left: 4, right: 4), | |||||
child: Text( | |||||
"预计返", | |||||
style: TextStyle( | |||||
color: Colors.deepOrangeAccent, | |||||
fontSize: 20.sp), | |||||
), | |||||
), | |||||
) | |||||
], | |||||
), | |||||
) | |||||
], | |||||
), | |||||
], | |||||
), | |||||
SizedBox( | |||||
height: 10.h, | |||||
), | |||||
Row( | |||||
crossAxisAlignment: CrossAxisAlignment.end, | |||||
children: <Widget>[ | |||||
Padding( | |||||
padding: const EdgeInsets.only(bottom: 2), | |||||
child: Text( | |||||
"券后", | |||||
style: TextStyle(fontSize: 20.sp, color: Colors.red), | |||||
), | |||||
), | |||||
Padding( | |||||
padding: | |||||
const EdgeInsets.only(bottom: 2, left: 4, right: 4), | |||||
child: Text( | |||||
"¥", | |||||
style: TextStyle(fontSize: 20.sp, color: Colors.red), | |||||
), | |||||
), | |||||
Text( | |||||
"999", | |||||
style: TextStyle( | |||||
fontSize: 32.sp, | |||||
color: Colors.red, | |||||
), | |||||
) | |||||
], | |||||
) | |||||
], | |||||
), | |||||
)) | |||||
], | |||||
); | |||||
} | |||||
_buildBottomItem() { | |||||
return Column( | |||||
children: <Widget>[ | |||||
SizedBox( | |||||
height: 24, | |||||
), | |||||
Row( | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Container( | |||||
margin: EdgeInsets.only(left: 20.w, right: 20.w), | |||||
decoration: BoxDecoration( | |||||
color: Colors.red, borderRadius: BorderRadius.circular(50)), | |||||
child: Center( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(12.0), | |||||
child: Text( | |||||
"合法化 ", | |||||
style: TextStyle(color: Colors.white, fontSize: 24.sp), | |||||
), | |||||
)), | |||||
)) | |||||
], | |||||
), | |||||
SizedBox( | |||||
height: 16, | |||||
), | |||||
Row( | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Container( | |||||
margin: EdgeInsets.only(left: 20.w, right: 20.w), | |||||
decoration: BoxDecoration( | |||||
color: Colors.red, borderRadius: BorderRadius.circular(50)), | |||||
child: Center( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(12.0), | |||||
child: Text( | |||||
"合法化 ", | |||||
style: TextStyle(color: Colors.white, fontSize: 24.sp), | |||||
), | |||||
)), | |||||
)) | |||||
], | |||||
) | |||||
], | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,183 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter/services.dart'; | |||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class IntellectSearchNoGoodsDialog extends StatefulWidget { | |||||
@override | |||||
_IntellectSearchNoGoodsDialogState createState() => | |||||
_IntellectSearchNoGoodsDialogState(); | |||||
} | |||||
class _IntellectSearchNoGoodsDialogState | |||||
extends State<IntellectSearchNoGoodsDialog> { | |||||
TextEditingController _textEditingController; | |||||
@override | |||||
void initState() { | |||||
_textEditingController = TextEditingController(); | |||||
_getClipBoardData(); | |||||
super.initState(); | |||||
} | |||||
///获取粘贴板内容 | |||||
_getClipBoardData() async { | |||||
ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); | |||||
_textEditingController.text = data.text; | |||||
setState(() {}); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.transparent, | |||||
body: Column( | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
Stack( | |||||
children: <Widget>[ | |||||
Container( | |||||
margin: EdgeInsets.only(top: 38.h, left: 92.w, right: 92.w), | |||||
padding: EdgeInsets.only( | |||||
top: (38 + 15).h, left: 30.w, right: 30.w, bottom: 48.h), | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
borderRadius: BorderRadius.circular(16)), | |||||
width: double.infinity, | |||||
child: Column( | |||||
children: <Widget>[_buildTopItem(), _buildBottomItem()], | |||||
), | |||||
), | |||||
Container( | |||||
height: 76.h, | |||||
child: Center( | |||||
child: Container( | |||||
color: Colors.red, | |||||
height: 76.h, | |||||
width: 216.w, | |||||
child: CachedNetworkImage( | |||||
imageUrl: "", | |||||
), | |||||
)), | |||||
), | |||||
], | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
_buildTopItem() { | |||||
return Container( | |||||
decoration: BoxDecoration(), | |||||
child: Column( | |||||
children: <Widget>[ | |||||
Text( | |||||
"猜你要搜索以下商品", | |||||
style: TextStyle(color: Colors.red, fontSize: 30.sp), | |||||
), | |||||
Container( | |||||
margin: EdgeInsets.only(top: 12), | |||||
decoration: BoxDecoration( | |||||
color: Colors.deepOrangeAccent, | |||||
borderRadius: BorderRadius.circular(10)), | |||||
child: TextField( | |||||
controller: _textEditingController, | |||||
textAlign: TextAlign.start, | |||||
decoration: InputDecoration( | |||||
contentPadding: EdgeInsets.only(left: 10, top: 10, bottom: 4), | |||||
border: InputBorder.none, | |||||
), | |||||
maxLines: 5, | |||||
), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
_buildBottomItem() { | |||||
return Column( | |||||
children: <Widget>[ | |||||
SizedBox( | |||||
height: 24, | |||||
), | |||||
Row( | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Container( | |||||
decoration: BoxDecoration( | |||||
color: Colors.red, borderRadius: BorderRadius.circular(50)), | |||||
child: Center( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(12.0), | |||||
child: Text( | |||||
"立即搜索 ", | |||||
style: TextStyle(color: Colors.white, fontSize: 24.sp), | |||||
), | |||||
)), | |||||
)) | |||||
], | |||||
), | |||||
SizedBox( | |||||
height: 16, | |||||
), | |||||
Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
children: <Widget>[ | |||||
Container( | |||||
height: 1, | |||||
width: 137.w, | |||||
color: Colors.deepOrange, | |||||
), | |||||
Text("搜索平台"), | |||||
Container( | |||||
height: 1, | |||||
width: 137.w, | |||||
color: Colors.deepOrange, | |||||
), | |||||
], | |||||
), | |||||
SizedBox( | |||||
height: 24, | |||||
), | |||||
Container( | |||||
height: 100.w, | |||||
child: ListView.builder( | |||||
scrollDirection: Axis.horizontal, | |||||
shrinkWrap: true, | |||||
itemCount: 10, | |||||
itemBuilder: _buildBottomListItem), | |||||
) | |||||
], | |||||
); | |||||
} | |||||
Widget _buildBottomListItem(BuildContext context, int index) { | |||||
return Container( | |||||
margin: EdgeInsets.only(left: 11,right: 11), | |||||
child: Column( | |||||
children: <Widget>[ | |||||
Container( | |||||
color: Colors.deepOrange, | |||||
child: Image.network( | |||||
"", | |||||
width: 60.w, | |||||
height: 60.w, | |||||
fit: BoxFit.fill, | |||||
), | |||||
), | |||||
SizedBox( | |||||
height: 2, | |||||
), | |||||
Text( | |||||
"淘宝", | |||||
style: TextStyle(fontSize: 22.sp), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,50 @@ | |||||
///智能粘贴板设置参数 | |||||
///杨华轩 | |||||
class IntellectSearchSetModel { | |||||
List<String> exclude; | |||||
String keywordAlpha; | |||||
String keywordAlphanum; | |||||
String keywordLimitMax; | |||||
String keywordLimitMin; | |||||
String keywordLimitState; | |||||
String keywordNum; | |||||
List<String> pvd; | |||||
String state; | |||||
IntellectSearchSetModel( | |||||
{this.exclude, | |||||
this.keywordAlpha, | |||||
this.keywordAlphanum, | |||||
this.keywordLimitMax, | |||||
this.keywordLimitMin, | |||||
this.keywordLimitState, | |||||
this.keywordNum, | |||||
this.pvd, | |||||
this.state}); | |||||
IntellectSearchSetModel.fromJson(Map<String, dynamic> json) { | |||||
exclude = json['exclude'].cast<String>(); | |||||
keywordAlpha = json['keyword_alpha'].toString(); | |||||
keywordAlphanum = json['keyword_alphanum'].toString(); | |||||
keywordLimitMax = json['keyword_limit_max'].toString(); | |||||
keywordLimitMin = json['keyword_limit_min'].toString(); | |||||
keywordLimitState = json['keyword_limit_state'].toString(); | |||||
keywordNum = json['keyword_num'].toString(); | |||||
pvd = json['pvd'].cast<String>(); | |||||
state = json['state'].toString(); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['exclude'] = this.exclude; | |||||
data['keyword_alpha'] = this.keywordAlpha; | |||||
data['keyword_alphanum'] = this.keywordAlphanum; | |||||
data['keyword_limit_max'] = this.keywordLimitMax; | |||||
data['keyword_limit_min'] = this.keywordLimitMin; | |||||
data['keyword_limit_state'] = this.keywordLimitState; | |||||
data['keyword_num'] = this.keywordNum; | |||||
data['pvd'] = this.pvd; | |||||
data['state'] = this.state; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,209 @@ | |||||
import 'dart:async'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_comm/util/extension/color.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SelectDateYMDialog extends StatefulWidget { | |||||
int currentYear; | |||||
int currentMonth; | |||||
SelectDateYMDialog({Key key, this.currentYear = 0, this.currentMonth = 0}) | |||||
: super(key: key) { | |||||
var date = DateTime.now(); | |||||
if (currentYear == 0) { | |||||
currentYear = date.year; | |||||
} | |||||
if (currentMonth == 0) { | |||||
currentMonth = date.month; | |||||
} | |||||
} | |||||
@override | |||||
_SelectDateYMDialogState createState() => _SelectDateYMDialogState(); | |||||
} | |||||
class _SelectDateYMDialogState extends State<SelectDateYMDialog> | |||||
with TickerProviderStateMixin { | |||||
List<int> yearDate = List(); | |||||
List<int> monthDate = List(); | |||||
int selectYearIndex = 0; | |||||
int selectMonthIndex = 0; | |||||
ScrollController _yearScrollController; | |||||
ScrollController _monthScrollController; | |||||
double _containerHeight = 0; | |||||
AnimationController _animationController; | |||||
Animation _animation; | |||||
@override | |||||
void initState() { | |||||
_monthScrollController = FixedExtentScrollController(); | |||||
for (int index = 0; index < 200; index++) { | |||||
yearDate.add(index + 1900); | |||||
if (index + 1900 == widget.currentYear) { | |||||
selectYearIndex = index; | |||||
} | |||||
} | |||||
for (int index = 0; index < 12; index++) { | |||||
monthDate.add(index + 1); | |||||
if (index + 1 == widget.currentMonth) { | |||||
selectMonthIndex = index; | |||||
} | |||||
} | |||||
_yearScrollController = | |||||
FixedExtentScrollController(initialItem: selectYearIndex); | |||||
_monthScrollController = | |||||
FixedExtentScrollController(initialItem: selectMonthIndex); | |||||
_animationController = new AnimationController( | |||||
duration: const Duration(milliseconds: 500), vsync: this); | |||||
final CurvedAnimation curve = | |||||
new CurvedAnimation(parent: _animationController, curve: Curves.ease); | |||||
_animation = new Tween(begin: 0.0, end: 250.0).animate(curve); | |||||
_animation.addListener(() { | |||||
setState(() {}); | |||||
}); | |||||
_animationController.forward(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.transparent, | |||||
body: Column( | |||||
mainAxisAlignment: MainAxisAlignment.end, | |||||
children: <Widget>[ | |||||
Container( | |||||
height: 56, | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
borderRadius: BorderRadius.only( | |||||
topLeft: Radius.circular(20), | |||||
topRight: Radius.circular(20))), | |||||
child: Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
GestureDetector( | |||||
child: Padding( | |||||
padding: const EdgeInsets.only( | |||||
left: 16, top: 8, bottom: 8, right: 16), | |||||
child: Text( | |||||
"取消", | |||||
style: TextStyle( | |||||
color: HexColor.fromHex("#FF999999"), | |||||
fontSize: 35.sp), | |||||
), | |||||
), | |||||
onTap: () { | |||||
Navigator.pop(context); | |||||
}, | |||||
), | |||||
Text("选择日期"), | |||||
GestureDetector( | |||||
child: Padding( | |||||
padding: const EdgeInsets.only( | |||||
right: 16, left: 16, bottom: 8, top: 8), | |||||
child: Text( | |||||
"确定", | |||||
style: TextStyle( | |||||
color: HexColor.fromHex("#FFFF4242"), | |||||
fontSize: 35.sp), | |||||
), | |||||
), | |||||
onTap: () { | |||||
Navigator.of(context).pop({ | |||||
"year": yearDate[selectYearIndex].toString(), | |||||
"month": monthDate[selectMonthIndex].toString() | |||||
}); | |||||
}, | |||||
) | |||||
], | |||||
), | |||||
), | |||||
Container( | |||||
height: _animation.value, | |||||
color: Colors.white, | |||||
child: Row( | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(8.0), | |||||
child: CupertinoPicker( | |||||
scrollController: _yearScrollController, | |||||
backgroundColor: Colors.white, | |||||
itemExtent: 40, | |||||
onSelectedItemChanged: (index) { | |||||
selectYearIndex = index; | |||||
setState(() {}); | |||||
}, | |||||
children: _buildItem(context))), | |||||
flex: 1, | |||||
), | |||||
Expanded( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(8.0), | |||||
child: CupertinoPicker( | |||||
scrollController: _monthScrollController, | |||||
backgroundColor: Colors.white, | |||||
itemExtent: 40, | |||||
onSelectedItemChanged: (index) { | |||||
selectMonthIndex = index; | |||||
setState(() {}); | |||||
}, | |||||
children: _buildItem2(context), | |||||
)), | |||||
flex: 1, | |||||
) | |||||
], | |||||
), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
_buildItem(BuildContext context) { | |||||
List<Widget> listWidget = List(); | |||||
for (int index = 0; index < yearDate.length; index++) { | |||||
listWidget.add(Container( | |||||
height: 40, | |||||
child: Center( | |||||
child: Text( | |||||
yearDate[index].toString() + "", | |||||
style: TextStyle( | |||||
color: | |||||
index == selectYearIndex ? Colors.redAccent : Colors.black26), | |||||
)), | |||||
)); | |||||
} | |||||
return listWidget; | |||||
} | |||||
_buildItem2(BuildContext context) { | |||||
List<Widget> listWidget = List(); | |||||
for (int index = 0; index < monthDate.length; index++) { | |||||
listWidget.add(Container( | |||||
height: 40, | |||||
child: Center( | |||||
child: Text(monthDate[index].toString() + "月", | |||||
style: TextStyle( | |||||
color: index == selectMonthIndex | |||||
? Colors.redAccent | |||||
: Colors.black26))))); | |||||
} | |||||
return listWidget; | |||||
} | |||||
} |
@@ -0,0 +1,135 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:intl/intl.dart'; | |||||
import 'package:provider/provider.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||||
import 'package:zhiying_base_widget/dialog/select_date_ym_dialog/select_date_ym_dialog.dart'; | |||||
import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | |||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; | |||||
import 'package:zhiying_base_widget/utils/contants.dart'; | |||||
import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||||
import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart'; | |||||
class BilDetailPage extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
const BilDetailPage(this.data, {Key key}) : super(key: key); | |||||
@override | |||||
_BilDetailPageState createState() => _BilDetailPageState(); | |||||
} | |||||
class _BilDetailPageState extends State<BilDetailPage> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Color(0xfff9f9f9), | |||||
body: MultiProvider( | |||||
providers: [ | |||||
ChangeNotifierProvider.value(value: MainPageNotifier()), | |||||
ChangeNotifierProvider.value(value: MainPageBgNotifier()), | |||||
], | |||||
child: BlocProvider<BilDetailPageBloc>( | |||||
bloc: BilDetailPageBloc(), | |||||
child: BilDetailPageContainer(data: widget.data), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} | |||||
class BilDetailPageContainer extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
const BilDetailPageContainer({Key key, this.data}) : super(key: key); | |||||
@override | |||||
_BilDetailPageContainerState createState() => _BilDetailPageContainerState(); | |||||
} | |||||
class _BilDetailPageContainerState extends State<BilDetailPageContainer> { | |||||
BilDetailPageBloc _bloc; | |||||
String showDate; | |||||
@override | |||||
void initState() { | |||||
_bloc = BlocProvider.of<BilDetailPageBloc>(context); | |||||
// showDate=DateFormat(DateFormat.YEAR_MONTH).parse(DateTime.now()); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return StreamBuilder( | |||||
builder: (context, sny) { | |||||
return Scaffold( | |||||
appBar: AppBar( | |||||
centerTitle: true, | |||||
title: Text("明细"), | |||||
), | |||||
body: Container( | |||||
child: ListView( | |||||
shrinkWrap: true, | |||||
children: <Widget>[ | |||||
_buildType(), | |||||
], | |||||
), | |||||
), | |||||
); | |||||
}, | |||||
); | |||||
} | |||||
_buildType() { | |||||
return Row( | |||||
children: <Widget>[ | |||||
SizedBox(width: 12.5), | |||||
InkWell( | |||||
onTap: (){ | |||||
///显示日期选择弹窗 | |||||
_selectDate(); | |||||
}, | |||||
child: Padding( | |||||
padding: const EdgeInsets.only(top: 8,bottom: 8), | |||||
child: Text("2020-08"), | |||||
), | |||||
), | |||||
Icon(Icons.arrow_drop_down), | |||||
Expanded( | |||||
child: Container( | |||||
height: 50, | |||||
child: ListView.builder( | |||||
scrollDirection: Axis.horizontal, | |||||
shrinkWrap: true, | |||||
itemCount: 3, | |||||
itemBuilder: (context, index) { | |||||
return Container( | |||||
margin: | |||||
EdgeInsets.only(top: 10, left: 8, right: 8, bottom: 10), | |||||
decoration: BoxDecoration( | |||||
color: Colors.grey[200], | |||||
borderRadius: BorderRadius.circular(50)), | |||||
child: Padding( | |||||
padding: const EdgeInsets.only(left: 16, right: 16), | |||||
child: Center( | |||||
child: Text( | |||||
"推广", | |||||
style: TextStyle(color: Colors.grey), | |||||
)), | |||||
), | |||||
); | |||||
}), | |||||
)) | |||||
], | |||||
); | |||||
} | |||||
void _selectDate() { | |||||
showDialog(context: context, builder: (context)=>SelectDateYMDialog()); | |||||
} | |||||
} |
@@ -0,0 +1,53 @@ | |||||
import 'dart:async'; | |||||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class BilDetailPageBloc extends BlocBase { | |||||
List<Map<String, dynamic>> _tabs = List(); | |||||
StreamController<List<Map<String, dynamic>>> _tabController = | |||||
StreamController<List<Map<String, dynamic>>>(); | |||||
Stream<List<Map<String, dynamic>>> get outData => _tabController.stream; | |||||
@override | |||||
void dispose() { | |||||
_tabController.close(); | |||||
_tabController = null; | |||||
} | |||||
loadData(String skipIdentifier) { | |||||
NetUtil.request('/api/v1/mod/${skipIdentifier}', method: NetMethod.GET, | |||||
onCache: (data) { | |||||
_loadData(data); | |||||
}, onSuccess: (data) { | |||||
_loadData(data); | |||||
}); | |||||
} | |||||
void refresh() {} | |||||
///处理加载的数据 | |||||
void _loadData(data) { | |||||
print(data["mod_lis"]); | |||||
var list = List.from(data["mod_list"]).map((v) { | |||||
return Map<String, dynamic>.from(v); | |||||
}).toList(); | |||||
_tabController.add(list); | |||||
} | |||||
void dateChange(DateChangeEvent dateChangeEvent){ | |||||
///日期变更后 | |||||
} | |||||
} | |||||
class DateChangeEvent{ | |||||
String date; | |||||
DateChangeEvent(this.date); | |||||
} |
@@ -0,0 +1,5 @@ | |||||
class BilDetailPageModel{ | |||||
} |
@@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | import 'package:pull_to_refresh/pull_to_refresh.dart'; | ||||
import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_bloc.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_bloc.dart'; | ||||
import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart'; | ||||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page_sk.dart'; | |||||
import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; | ||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
@@ -120,7 +121,7 @@ class _GoodsDetailsContainerState extends State<GoodsDetailsContainer> { | |||||
if (state is GoodsDetailsPageLoadedState) { | if (state is GoodsDetailsPageLoadedState) { | ||||
return _getMainWidget(state?.model); | return _getMainWidget(state?.model); | ||||
} | } | ||||
return _getMainWidget(null); | |||||
return GoodsDetailsPageSkeleton(); | |||||
}, | }, | ||||
), | ), | ||||
), | ), | ||||
@@ -0,0 +1,46 @@ | |||||
import 'package:zhiying_base_widget/widgets/goods_details/coupon/counpon_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/goods_details/store/store_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/goods_details/upgrade_tip/upgrade_tip_sk.dart'; | |||||
import 'package:zhiying_comm/util/shimmer_util.dart'; | |||||
import 'package:flutter/material.dart'; | |||||
class GoodsDetailsPageSkeleton extends StatelessWidget { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Stack( | |||||
children: <Widget>[ | |||||
Column( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
/// 轮播图 | |||||
GoodsDetailsSlideBannerSkeleton(), | |||||
SizedBox(height: 12.5), | |||||
/// 更新 | |||||
UpgradeTipSkeleton(), | |||||
/// 商店 | |||||
StoreSkeleton(), | |||||
/// 优惠卷 | |||||
CounponSkeleton(), | |||||
SizedBox(height: 15), | |||||
/// 图片 | |||||
ShimmerUtil.getShimmerWidget(width: double.infinity, height: 40), | |||||
ShimmerUtil.getShimmerWidget(width: double.infinity, height: 40), | |||||
], | |||||
), | |||||
Align( | |||||
alignment: Alignment.bottomCenter, | |||||
child: GoodsDetailsFooterSkeleton(), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -36,6 +36,7 @@ class _HomePageState extends State<HomePage> { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
ScreenUtil.init(context, width: 750, height: 1334); | |||||
print('home_page build'); | print('home_page build'); | ||||
List<Map<String, dynamic>> tabs = _data; | List<Map<String, dynamic>> tabs = _data; | ||||
if (tabs == null || tabs.length == 0) { | if (tabs == null || tabs.length == 0) { | ||||
@@ -2,9 +2,13 @@ import 'package:flutter/cupertino.dart'; | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | import 'package:pull_to_refresh/pull_to_refresh.dart'; | ||||
import 'package:zhiying_base_widget/dialog/global_dialog/intellect_search_goods_dialog/intellect_create.dart'; | |||||
import 'package:zhiying_base_widget/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_goods_dialog.dart'; | |||||
import 'package:zhiying_base_widget/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_no_goods_dialog.dart'; | |||||
import 'package:zhiying_base_widget/pages/main_page/main_page_bloc.dart'; | import 'package:zhiying_base_widget/pages/main_page/main_page_bloc.dart'; | ||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | ||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; | import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; | ||||
import 'package:zhiying_base_widget/utils/contants.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_auth/home_auth.dart'; | import 'package:zhiying_base_widget/widgets/home/home_auth/home_auth.dart'; | ||||
import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart'; | import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart'; | ||||
import 'package:zhiying_comm/util/base_bloc.dart'; | import 'package:zhiying_comm/util/base_bloc.dart'; | ||||
@@ -47,7 +51,8 @@ class _MainPageContainer extends StatefulWidget { | |||||
_MainPageContainerState createState() => _MainPageContainerState(); | _MainPageContainerState createState() => _MainPageContainerState(); | ||||
} | } | ||||
class _MainPageContainerState extends State<_MainPageContainer> { | |||||
class _MainPageContainerState extends State<_MainPageContainer> | |||||
with WidgetsBindingObserver { | |||||
bool _isEnded = false; | bool _isEnded = false; | ||||
ScrollController _controller = ScrollController(); | ScrollController _controller = ScrollController(); | ||||
MainPageBloc _bloc; | MainPageBloc _bloc; | ||||
@@ -62,9 +67,17 @@ class _MainPageContainerState extends State<_MainPageContainer> { | |||||
// _refreshController.loadComplete(); | // _refreshController.loadComplete(); | ||||
} | } | ||||
@override | |||||
void didChangeAppLifecycleState(AppLifecycleState state) async { | |||||
///智能粘贴板 | |||||
// IntellectCreate.checkAndCreate(state, context); | |||||
super.didChangeAppLifecycleState(state); | |||||
} | |||||
@override | @override | ||||
void dispose() { | void dispose() { | ||||
_controller.dispose(); | _controller.dispose(); | ||||
WidgetsBinding.instance.removeObserver(this); | |||||
super.dispose(); | super.dispose(); | ||||
} | } | ||||
@@ -88,6 +101,9 @@ class _MainPageContainerState extends State<_MainPageContainer> { | |||||
Provider.of<MainPageNotifier>(context, listen: false).reset(); | Provider.of<MainPageNotifier>(context, listen: false).reset(); | ||||
} | } | ||||
}); | }); | ||||
///监听app生命周期变化 | |||||
// WidgetsBinding.instance.addObserver(this); | |||||
IntellectCreate.checkAndCreateFirst(context); | |||||
super.initState(); | super.initState(); | ||||
} | } | ||||
@@ -37,6 +37,12 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> { | |||||
/// 初始化 | /// 初始化 | ||||
Stream<SearchState> _mapInitEventToState(SearchInitEvent event) async* { | Stream<SearchState> _mapInitEventToState(SearchInitEvent event) async* { | ||||
/// 获取缓存的数据 | |||||
var cache = await repository.fetchCachedData(event.model); | |||||
if(!EmptyUtil.isEmpty(cache)){ | |||||
print('缓存数据'); | |||||
yield SearchLoadedState(model: cache); | |||||
} | |||||
/// 获取数据 | /// 获取数据 | ||||
var result = await repository.fetchInit(event.model); | var result = await repository.fetchInit(event.model); | ||||
Logger.log('result = ${result.toString()}'); | Logger.log('result = ${result.toString()}'); | ||||
@@ -5,7 +5,7 @@ class SearchRepository { | |||||
/// 获取网络数据 | /// 获取网络数据 | ||||
Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> model) async { | Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> model) async { | ||||
var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_index', method: NetMethod.GET); | |||||
var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_index', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | ||||
try { | try { | ||||
_pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | _pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | ||||
@@ -18,7 +18,15 @@ class SearchRepository { | |||||
} | } | ||||
/// 获取缓存数据 | /// 获取缓存数据 | ||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> model) {} | |||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> model) async{ | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/pub.flutter.search_index'); | |||||
try { | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
return List.from(result['mod_list']); | |||||
} | |||||
}catch(e){} | |||||
return null; | |||||
} | |||||
/// 搜索的方法 | /// 搜索的方法 | ||||
Future<void> fetchSearchSubmit(final String model) async { | Future<void> fetchSearchSubmit(final String model) async { | ||||
@@ -0,0 +1,47 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:equatable/equatable.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/item/bloc/search_item_repostitory.dart'; | |||||
import 'package:zhiying_comm/util/empty_util.dart'; | |||||
part 'search_item_page_event.dart'; | |||||
part 'search_item_page_state.dart'; | |||||
class SearchItemPageBloc extends Bloc<SearchItemPageEvent, SearchItemPageState> { | |||||
// SearchItemPageBloc() : super(SearchItemPageInitial()); | |||||
SearchItemRepository repository; | |||||
SearchItemPageBloc({@required this.repository}); | |||||
@override | |||||
// TODO: implement initialState | |||||
SearchItemPageState get initialState => SearchItemPageInitial(); | |||||
@override | |||||
Stream<SearchItemPageState> mapEventToState( | |||||
SearchItemPageEvent event, | |||||
) async* { | |||||
/// 初始化 | |||||
if (event is SearchItemPageInitEvent) { | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<SearchItemPageState> _mapInitEventToState(SearchItemPageInitEvent event) async* { | |||||
var cache = await repository.fetchCachedData(event.model); | |||||
if(!EmptyUtil.isEmpty(cache)){ | |||||
yield SearchItemLoadedState(model: cache); | |||||
} | |||||
var result = await repository.fetchInit(event.model); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchItemLoadedState(model: result); | |||||
} else { | |||||
yield SearchItemErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
part of 'search_item_page_bloc.dart'; | |||||
abstract class SearchItemPageEvent extends Equatable { | |||||
const SearchItemPageEvent(); | |||||
} | |||||
/// 初始化 | |||||
class SearchItemPageInitEvent extends SearchItemPageEvent { | |||||
final Map<String, dynamic> model; | |||||
const SearchItemPageInitEvent({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} |
@@ -0,0 +1,26 @@ | |||||
part of 'search_item_page_bloc.dart'; | |||||
abstract class SearchItemPageState extends Equatable { | |||||
const SearchItemPageState(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
class SearchItemPageInitial extends SearchItemPageState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 数据加载成功 | |||||
class SearchItemLoadedState extends SearchItemPageState { | |||||
List<Map<String, dynamic>> model; | |||||
SearchItemLoadedState({this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 数据加载失败 | |||||
class SearchItemErrorState extends SearchItemPageState {} |
@@ -0,0 +1,34 @@ | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchItemRepository { | |||||
List<Map<String, dynamic>> _pageData = []; | |||||
/// 获取网络数据 | |||||
Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> model) async { | |||||
String skip_identifier = model['skip_identifier']; | |||||
var result = await NetUtil.post('/api/v1/mod/$skip_identifier', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | |||||
try { | |||||
_pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | |||||
return _pageData; | |||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取缓存数据 | |||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> model) async { | |||||
String skip_identifier = model['skip_identifier']; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skip_identifier'); | |||||
try { | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
return List.from(result['mod_list']); | |||||
} | |||||
}catch(e){} | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,121 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/item/bloc/search_item_page_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/item/bloc/search_item_repostitory.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
class SearchItemPage extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
const SearchItemPage(this.data); | |||||
@override | |||||
_SearchItemPageState createState() => _SearchItemPageState(); | |||||
} | |||||
class _SearchItemPageState extends State<SearchItemPage> with AutomaticKeepAliveClientMixin { | |||||
@override | |||||
bool get wantKeepAlive => true; | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<SearchItemPageBloc>( | |||||
create: (_) => SearchItemPageBloc(repository: SearchItemRepository())..add(SearchItemPageInitEvent(model: widget?.data)), | |||||
child: SearchItemPageContainer(), | |||||
); | |||||
} | |||||
} | |||||
class SearchItemPageContainer extends StatefulWidget { | |||||
@override | |||||
_SearchItemPageContainerState createState() => _SearchItemPageContainerState(); | |||||
} | |||||
class _SearchItemPageContainerState extends State<SearchItemPageContainer> { | |||||
RefreshController _refreshController; | |||||
ScrollController _controller; | |||||
@override | |||||
void initState() { | |||||
_refreshController = RefreshController(initialRefresh: false); | |||||
_controller = ScrollController(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_refreshController?.dispose(); | |||||
_controller?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocConsumer<SearchItemPageBloc, SearchItemPageState>( | |||||
listener: (BuildContext context, SearchItemPageState state) { | |||||
if (state is SearchItemErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchItemErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
print('currente state = $state'); | |||||
if (state is SearchItemLoadedState) { | |||||
return _getMainWidget(state?.model ?? null); | |||||
} | |||||
/// 骨架屏幕 | |||||
return _getMainWidget(null); | |||||
}, | |||||
); | |||||
} | |||||
/// 主视图 | |||||
Widget _getMainWidget(List<Map<String, dynamic>> datas) { | |||||
return Scaffold( | |||||
backgroundColor: HexColor.fromHex('#F9F9F9'), | |||||
body: SmartRefresher( | |||||
enablePullDown: false, | |||||
enablePullUp: true, | |||||
footer: ClassicFooter(), | |||||
header: WaterDropHeader(), | |||||
controller: _refreshController, | |||||
child: Container( | |||||
width: double.infinity, | |||||
child: CustomScrollView( | |||||
controller: _controller, | |||||
slivers: _createContentWidget(datas), | |||||
))), | |||||
); | |||||
} | |||||
/// 构造整体视图 | |||||
List<Widget> _createContentWidget(List<Map<String, dynamic>> datas) { | |||||
List<Widget> list = []; | |||||
int length = datas?.length ?? 0; | |||||
if (length > 0) { | |||||
for (int i = 0; i < datas.length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
} else { | |||||
list.add(SliverToBoxAdapter( | |||||
/// TODO 改成骨架图 | |||||
child: Container(child: Text('暂无数据~')), | |||||
)); | |||||
} | |||||
return list; | |||||
} | |||||
} |
@@ -0,0 +1,59 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:shared_preferences/shared_preferences.dart'; | |||||
class SearchTagNotifier with ChangeNotifier { | |||||
///文本标签集合 | |||||
List<String> _tagList = []; | |||||
/// 保存历史标签的sp key | |||||
static final String _SP_HOISTROY_KEY = 'hoistroyTag'; | |||||
/// 最大存储条数 | |||||
static final int _MAX_COUNT = 10; | |||||
/// 初始化历史搜索标签 | |||||
Future<List<String>> getHistoryTag() async { | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
String jsonStr = prefs.getString(_SP_HOISTROY_KEY); | |||||
if (null != jsonStr && jsonStr.length > 0) { | |||||
final Map jsonMap = jsonDecode(jsonStr); | |||||
if (jsonMap != null && jsonMap.length > 0) { | |||||
jsonMap.forEach((key, value) => _tagList.insert(0, value)); | |||||
} | |||||
} | |||||
return _tagList; | |||||
} | |||||
/// 添加搜索 | |||||
void addTag(String tag) async { | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
String jsonStr = prefs.getString(_SP_HOISTROY_KEY); | |||||
if (null != jsonStr && jsonStr.length > 0) { | |||||
final Map jsonMap = jsonDecode(jsonStr); | |||||
jsonMap[tag.toString()] = tag.toString(); | |||||
_tagList.insert(0, tag); // 第一位 | |||||
if (_tagList.length > _MAX_COUNT) { | |||||
jsonMap.remove(_tagList[_tagList.length - 1]); | |||||
_tagList.removeAt(_tagList.length - 1); | |||||
} | |||||
prefs.setString(_SP_HOISTROY_KEY, jsonEncode(jsonMap)); | |||||
} else { | |||||
prefs.setString(_SP_HOISTROY_KEY, jsonEncode({'${tag.toString()}': '${tag.toString()}'})); | |||||
_tagList.add(tag); | |||||
} | |||||
notifyListeners(); | |||||
} | |||||
/// 请空 | |||||
void clear() async{ | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
// String jsonStr = prefs.getString(_SP_HOISTROY_KEY); | |||||
prefs.setString(_SP_HOISTROY_KEY, ''); | |||||
_tagList.clear(); | |||||
notifyListeners(); | |||||
} | |||||
} |
@@ -1,6 +1,10 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
import 'package:provider/provider.dart'; | |||||
import 'bloc/search_bloc.dart'; | import 'bloc/search_bloc.dart'; | ||||
import 'bloc/search_repository.dart'; | import 'bloc/search_repository.dart'; | ||||
@@ -15,9 +19,30 @@ class SearchPage extends StatelessWidget { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return BlocProvider<SearchBloc>( | |||||
create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), | |||||
child: SearchPageContianer(), | |||||
return MultiProvider( | |||||
providers: [ | |||||
ChangeNotifierProvider.value(value: SearchTagNotifier()) | |||||
], | |||||
child: MultiProvider( | |||||
providers: [ | |||||
/// 搜索页面的bloc | |||||
BlocProvider<SearchBloc>( | |||||
create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), | |||||
), | |||||
/// 输入框联想的bloc | |||||
BlocProvider<SearchThinkBloc>( | |||||
create: (_)=> SearchThinkBloc(SearchThinkRepository()), | |||||
), | |||||
], | |||||
child: SearchPageContianer(), | |||||
), | |||||
// child: BlocProvider<SearchBloc>( | |||||
// create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), | |||||
// child: SearchPageContianer(), | |||||
// ), | |||||
); | ); | ||||
} | } | ||||
} | } | ||||
@@ -30,17 +55,15 @@ class SearchPageContianer extends StatefulWidget { | |||||
class _SearchPageContianerState extends State<SearchPageContianer> { | class _SearchPageContianerState extends State<SearchPageContianer> { | ||||
/// tab轮播 | /// tab轮播 | ||||
TabController _tabController; | TabController _tabController; | ||||
ScrollController _controller = ScrollController(); | |||||
@override | @override | ||||
void initState() { | void initState() { | ||||
_tabController = TabController(length:0, vsync: ScrollableState()); | |||||
_tabController = TabController(length: 6, vsync: ScrollableState()); | |||||
super.initState(); | super.initState(); | ||||
} | } | ||||
@override | @override | ||||
void dispose() { | void dispose() { | ||||
_controller?.dispose(); | |||||
_tabController?.dispose(); | _tabController?.dispose(); | ||||
super.dispose(); | super.dispose(); | ||||
} | } | ||||
@@ -94,44 +117,64 @@ class _SearchPageContianerState extends State<SearchPageContianer> { | |||||
Widget _getMainWidget(List<Map<String, dynamic>> datas) { | Widget _getMainWidget(List<Map<String, dynamic>> datas) { | ||||
return Scaffold( | return Scaffold( | ||||
backgroundColor: Colors.white, | backgroundColor: Colors.white, | ||||
body: CustomScrollView( | |||||
controller: _controller, | |||||
slivers: _createContent(context, datas ?? []), | |||||
body: Column( | |||||
children: _createContentWidget(datas), | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
List<Widget> _createContent(BuildContext context, List<Map<String, dynamic>> datas) { | |||||
List<Widget> list = List(); | |||||
List<Widget> _createContentWidget(List<Map<String, dynamic>> datas) { | |||||
List<Widget> list = []; | |||||
int length = datas?.length ?? 0; | int length = datas?.length ?? 0; | ||||
if (length <= 0) { | if (length <= 0) { | ||||
list.add(SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 200, | |||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | |||||
/// 骨架屏幕? | |||||
list.add(Container( | |||||
height: 200, | |||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | ), | ||||
)); | )); | ||||
return list; | |||||
} | |||||
for (int i = 0; i < 3; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} else { | |||||
for (int i = 0; i < datas.length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: false, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
} | } | ||||
list.add(SliverFillRemaining( | |||||
child: Text('etstssss et'), | |||||
)); | |||||
return list; | return list; | ||||
} | } | ||||
// List<Widget> _createContent(BuildContext context, List<Map<String, dynamic>> datas) { | |||||
// List<Widget> list = List(); | |||||
// | |||||
// int length = datas?.length ?? 0; | |||||
// | |||||
// if (length <= 0) { | |||||
// list.add(SliverToBoxAdapter( | |||||
// child: Container( | |||||
// height: 200, | |||||
// child: Center( | |||||
// child: Text('暂时无数据哦~'), | |||||
// ), | |||||
// ), | |||||
// )); | |||||
// return list; | |||||
// } | |||||
// | |||||
// for (int i = 0; i < 3; i++) { | |||||
// WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
// print('item.modName ${item.modName}'); | |||||
// list.addAll(WidgetFactory.create( | |||||
// item.modName, | |||||
// isSliver: true, | |||||
// model: datas[i], | |||||
// )); | |||||
// } | |||||
// | |||||
// return list; | |||||
// } | |||||
} | } |
@@ -1,183 +0,0 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'bloc/search_bloc.dart'; | |||||
import 'bloc/search_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchPage2 extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
const SearchPage2(this.data); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<SearchBloc>( | |||||
create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), | |||||
child: SearchPage2Container(), | |||||
); | |||||
} | |||||
} | |||||
class SearchPage2Container extends StatefulWidget { | |||||
@override | |||||
_SearchPage2ContainerState createState() => _SearchPage2ContainerState(); | |||||
} | |||||
class _SearchPage2ContainerState extends State<SearchPage2Container> { | |||||
TabController _controller; | |||||
@override | |||||
void initState() { | |||||
_controller = TabController(length: tabTitle.length, vsync: ScrollableState()); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_controller?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return MediaQuery.removePadding( | |||||
removeTop: true, | |||||
context: context, | |||||
child: Container( | |||||
width: double.infinity, | |||||
child: BlocConsumer<SearchBloc, SearchState>( | |||||
listener: (BuildContext context, SearchState state) { | |||||
if (state is SearchErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchErrorState) { | |||||
return false; | |||||
} | |||||
/// 搜索成功,跳转结果页面 | |||||
if (current is SearchSubmitSuccessState) { | |||||
return false; | |||||
} | |||||
/// 搜索失败,不进行build | |||||
if (current is SearchSubmitErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
print('currente state = $state'); | |||||
if (state is SearchLoadedState) { | |||||
return _getMainWidget(state?.model); | |||||
} | |||||
/// 骨架屏幕 | |||||
return _getMainWidget(null); | |||||
}, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 主视图 | |||||
Widget _getMainWidget(List<Map<String, dynamic>> datas){ | |||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: NestedScrollView( | |||||
headerSliverBuilder: (context, bool){ | |||||
return _createHeadWidget(context, datas); | |||||
}, | |||||
body: ListView( | |||||
children: <Widget>[ | |||||
Text('sss') | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 头部视图 | |||||
List<Widget> _createHeadWidget(BuildContext context, List<Map<String, dynamic>> datas){ | |||||
List<Widget> list = []; | |||||
int length = datas?.length?? 0; | |||||
if (length <= 0) { | |||||
list.add(SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 200, | |||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | |||||
), | |||||
)); | |||||
return list; | |||||
} | |||||
for (int i = 0; i < 2; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
list.add(_getTabbar()); | |||||
return list; | |||||
} | |||||
var tabTitle = [ | |||||
'页面1', | |||||
'页面2', | |||||
'页面3', | |||||
]; | |||||
Widget _getTabbar(){ | |||||
/// 悬停TabBar | |||||
return SliverPersistentHeader( | |||||
delegate: new SliverTabBarDelegate( | |||||
TabBar( | |||||
controller: _controller, | |||||
tabs: tabTitle.map((f) => Tab(text: f)).toList(), | |||||
indicatorColor: Colors.red, | |||||
unselectedLabelColor: Colors.black, | |||||
labelColor: Colors.red, | |||||
), | |||||
), | |||||
pinned: true, | |||||
); | |||||
} | |||||
} | |||||
class SliverTabBarDelegate extends SliverPersistentHeaderDelegate { | |||||
final TabBar widget; | |||||
const SliverTabBarDelegate(this.widget) | |||||
: assert(widget != null); | |||||
@override | |||||
Widget build( | |||||
BuildContext context, double shrinkOffset, bool overlapsContent) { | |||||
return Container( color:Colors.white,child: this.widget); | |||||
} | |||||
@override | |||||
bool shouldRebuild(SliverTabBarDelegate oldDelegate) { | |||||
return false; | |||||
} | |||||
@override | |||||
double get maxExtent => widget.preferredSize.height; | |||||
@override | |||||
double get minExtent => widget.preferredSize.height; | |||||
} |
@@ -1,148 +0,0 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'bloc/search_bloc.dart'; | |||||
import 'bloc/search_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchPage3 extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
const SearchPage3(this.data); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<SearchBloc>( | |||||
create: (_) => SearchBloc(repository: SearchRepository())..add(SearchInitEvent(model: data)), | |||||
child: SearchPage3Container(), | |||||
); | |||||
} | |||||
} | |||||
class SearchPage3Container extends StatefulWidget { | |||||
@override | |||||
_SearchPage3ContainerState createState() => _SearchPage3ContainerState(); | |||||
} | |||||
class _SearchPage3ContainerState extends State<SearchPage3Container> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return MediaQuery.removePadding( | |||||
removeTop: true, | |||||
context: context, | |||||
child: Container( | |||||
width: double.infinity, | |||||
child: BlocConsumer<SearchBloc, SearchState>( | |||||
listener: (BuildContext context, SearchState state) { | |||||
if (state is SearchErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchErrorState) { | |||||
return false; | |||||
} | |||||
/// 搜索成功,跳转结果页面 | |||||
if (current is SearchSubmitSuccessState) { | |||||
return false; | |||||
} | |||||
/// 搜索失败,不进行build | |||||
if (current is SearchSubmitErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
print('currente state = $state'); | |||||
if (state is SearchLoadedState) { | |||||
return _getMainWidget(state?.model); | |||||
} | |||||
/// 骨架屏幕 | |||||
return _getMainWidget(null); | |||||
}, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 主视图 | |||||
Widget _getMainWidget(List<Map<String, dynamic>> datas){ | |||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: NestedScrollView( | |||||
headerSliverBuilder: (context, bool){ | |||||
return _createHeadWidget(context, datas); | |||||
}, | |||||
body: Container( | |||||
child: Text('testssfee'), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 头部视图 | |||||
List<Widget> _createHeadWidget(BuildContext context, List<Map<String, dynamic>> datas){ | |||||
List<Widget> list = []; | |||||
int length = datas?.length?? 0; | |||||
if (length <= 0) { | |||||
list.add(SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 200, | |||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | |||||
), | |||||
)); | |||||
return list; | |||||
} | |||||
for (int i = 0; i < 3; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
return list; | |||||
} | |||||
/// 子视图 | |||||
List<Widget> _createContent(BuildContext context, List<Map<String, dynamic>> datas) { | |||||
List<Widget> list = List(); | |||||
/// datas.length - 1 为最后一个在底部 | |||||
for (int i = 0; i < datas.length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
if (list.length <= 0) { | |||||
list.add(SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 200, | |||||
child: Center( | |||||
child: Text('暂时无数据哦~'), | |||||
), | |||||
), | |||||
)); | |||||
} | |||||
return list; | |||||
} | |||||
} | |||||
@@ -0,0 +1,46 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:equatable/equatable.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/bloc/search_result_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
part 'search_result_event.dart'; | |||||
part 'search_result_state.dart'; | |||||
class SearchResultBloc extends Bloc<SearchResultEvent, SearchResultState> { | |||||
// SearchResultBloc() : super(SearchResultInitial()); | |||||
SearchResultRepository repository; | |||||
SearchResultBloc({@required this.repository}); | |||||
@override | |||||
SearchResultState get initialState => SearchResultInitial(); | |||||
@override | |||||
Stream<SearchResultState> mapEventToState( | |||||
SearchResultEvent event, | |||||
) async* { | |||||
if (event is SearchResultInitEvent) { | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<SearchResultState> _mapInitEventToState(SearchResultInitEvent event) async* { | |||||
var cache = await repository.fetchCachedData(event.model); | |||||
if(!EmptyUtil.isEmpty(cache)){ | |||||
yield SearchResultLoadedState(model: cache); | |||||
} | |||||
var result = await repository.fetchInit(event.model); | |||||
if(!EmptyUtil.isEmpty(result)){ | |||||
yield SearchResultLoadedState(model: result); | |||||
}else{ | |||||
yield SearchResultErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,18 @@ | |||||
part of 'search_result_bloc.dart'; | |||||
abstract class SearchResultEvent extends Equatable { | |||||
const SearchResultEvent(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 初始化数据 | |||||
class SearchResultInitEvent extends SearchResultEvent { | |||||
final Map<String, dynamic> model; | |||||
const SearchResultInitEvent({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} |
@@ -0,0 +1,60 @@ | |||||
import 'dart:convert'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchResultRepository { | |||||
List<Map<String, dynamic>> _pageData = []; | |||||
/// 获取网络数据 | |||||
Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> model) async { | |||||
String keywords = model.containsKey('keywords') ? model['keywords'] : ''; | |||||
String type = model.containsKey('type') ? model['type'] : 'taobao'; | |||||
var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_result', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | |||||
try { | |||||
List<Map<String, dynamic>> modList = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | |||||
modList.forEach((Map<String, dynamic> item) { | |||||
var data = jsonDecode(item['data']); | |||||
data['keywords'] = keywords; | |||||
data['type'] = type; | |||||
item['data'] = jsonEncode(data); | |||||
_pageData.add(item); | |||||
}); | |||||
return _pageData; | |||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取缓存数据 | |||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> model) async { | |||||
String keywords = model.containsKey('keywords') ? model['keywords'] : ''; | |||||
String type = model.containsKey('type') ? model['type'] : 'taobao'; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/pub.flutter.search_result'); | |||||
try { | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
// return List.from(result['mod_list']); | |||||
List<Map<String, dynamic>> modList = List.from(result['mod_list']); | |||||
List<Map<String, dynamic>> _pageData = []; | |||||
modList.forEach((Map<String, dynamic> item) { | |||||
var data = jsonDecode(item['data']); | |||||
data['keywords'] = keywords; | |||||
data['type'] = type; | |||||
item['data'] = jsonEncode(data); | |||||
_pageData.add(item); | |||||
}); | |||||
return _pageData; | |||||
} | |||||
} catch (e) {} | |||||
return null; | |||||
} | |||||
/// 搜索的方法 | |||||
Future<void> fetchSearchSubmit(final String model) async { | |||||
var result = await NetUtil.post(''); | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
part of 'search_result_bloc.dart'; | |||||
abstract class SearchResultState extends Equatable { | |||||
const SearchResultState(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
class SearchResultInitial extends SearchResultState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 数据加载完毕 | |||||
class SearchResultLoadedState extends SearchResultState { | |||||
List<Map<String, dynamic>> model; | |||||
SearchResultLoadedState({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 数据加载失败 | |||||
class SearchResultErrorState extends SearchResultState {} |
@@ -0,0 +1,48 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:equatable/equatable.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/item/bloc/search_result_item_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
part 'search_result_item_event.dart'; | |||||
part 'search_result_item_state.dart'; | |||||
class SearchResultItemBloc extends Bloc<SearchResultItemEvent, SearchResultItemState> { | |||||
// SearchResultItemBloc() : super(SearchResultItemInitial()); | |||||
SearchResultItemRepository repository; | |||||
@override | |||||
SearchResultItemState get initialState => SearchResultItemInitial(); | |||||
SearchResultItemBloc({@required this.repository}); | |||||
@override | |||||
Stream<SearchResultItemState> mapEventToState( | |||||
SearchResultItemEvent event, | |||||
) async* { | |||||
if (event is SearchResultItemInitEvent) { | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<SearchResultItemState> _mapInitEventToState(SearchResultItemInitEvent event) async* { | |||||
/// 获取缓存数据 | |||||
var cache = await repository.fetchCacheData(event.model); | |||||
if (!EmptyUtil.isEmpty(cache)) { | |||||
yield SearchResultItemLoadedState(model: cache); | |||||
} | |||||
/// 访问网络数据 | |||||
var result = await repository.fetchInitData(event.model); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultItemLoadedState(model: result); | |||||
} else { | |||||
yield SearchResultItemErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
part of 'search_result_item_bloc.dart'; | |||||
abstract class SearchResultItemEvent extends Equatable { | |||||
const SearchResultItemEvent(); | |||||
} | |||||
/// 初始化 | |||||
class SearchResultItemInitEvent extends SearchResultItemEvent{ | |||||
final Map<String, dynamic> model; | |||||
const SearchResultItemInitEvent({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} |
@@ -0,0 +1,55 @@ | |||||
import 'dart:convert'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchResultItemRepository { | |||||
List<Map<String, dynamic>> _pageData; | |||||
/// 初始化 | |||||
Future<List<Map<String, dynamic>>> fetchInitData(final Map<String, dynamic> model) async { | |||||
String type = model['type']; | |||||
String keywords = model.containsKey('keywords') ? model['keywords'] : ''; | |||||
if (EmptyUtil.isEmpty(type)) return null; | |||||
var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_result.$type', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | |||||
try { | |||||
List<Map<String, dynamic>> modList = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | |||||
modList.forEach((Map<String, dynamic> item) { | |||||
var data = jsonDecode(item['data']); | |||||
data['keywords'] = keywords; | |||||
item['data'] = jsonEncode(data); | |||||
_pageData.add(item); | |||||
}); | |||||
return _pageData; | |||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取缓存数据 | |||||
Future<List<Map<String, dynamic>>> fetchCacheData(final Map<String, dynamic> model) async { | |||||
String type = model['type'] ?? ''; | |||||
String keywords = model.containsKey('keywords') ? model['keywords'] : ''; | |||||
if (EmptyUtil.isEmpty(type)) return null; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/pub.flutter.search_result.$type'); | |||||
try { | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
List<Map<String, dynamic>> modList = List.from(result['mod_list']); | |||||
List<Map<String, dynamic>> _pageData = []; | |||||
modList.forEach((Map<String, dynamic> item) { | |||||
var data = jsonDecode(item['data']); | |||||
data['keywords'] = keywords; | |||||
item['data'] = jsonEncode(data); | |||||
_pageData.add(item); | |||||
}); | |||||
return _pageData; | |||||
} | |||||
} catch (e) {} | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
part of 'search_result_item_bloc.dart'; | |||||
abstract class SearchResultItemState extends Equatable { | |||||
const SearchResultItemState(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
class SearchResultItemInitial extends SearchResultItemState {} | |||||
/// 数据加载完毕 | |||||
class SearchResultItemLoadedState extends SearchResultItemState { | |||||
List<Map<String, dynamic>> model; | |||||
SearchResultItemLoadedState({@required this.model}); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 数据加载失败 | |||||
class SearchResultItemErrorState extends SearchResultItemState {} |
@@ -0,0 +1,16 @@ | |||||
import 'package:flutter/material.dart'; | |||||
class SearchResultItemPageNotifier with ChangeNotifier { | |||||
bool scrollEnd = false; | |||||
// 加载更多数据 | |||||
void loadMore() { | |||||
scrollEnd = true; | |||||
notifyListeners(); | |||||
} | |||||
void reset() { | |||||
scrollEnd = false; | |||||
notifyListeners(); | |||||
} | |||||
} |
@@ -0,0 +1,195 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/item/bloc/search_result_item_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/item/bloc/search_result_item_repository.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/skeleton/home_goods_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'package:provider/provider.dart'; | |||||
import 'notifier/search_result_item_page_notifier.dart'; | |||||
class SearchResultItemPage extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
const SearchResultItemPage(this.data); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return MultiProvider( | |||||
providers: [ | |||||
ChangeNotifierProvider.value(value: SearchResultItemPageNotifier()), | |||||
], | |||||
// child: BlocProvider<SearchResultItemBloc>( | |||||
// create: (_) => SearchResultItemBloc(repository: SearchResultItemRepository())..add(SearchResultItemInitEvent(model: data)), | |||||
// child: SearchResultItemPageContianer(), | |||||
// ), | |||||
child: MultiBlocProvider( | |||||
providers: [ | |||||
/// 视图BLOC | |||||
BlocProvider<SearchResultItemBloc>( | |||||
create: (_) => SearchResultItemBloc(repository: SearchResultItemRepository())..add(SearchResultItemInitEvent(model: data)), | |||||
), | |||||
/// 商品列表Bloc | |||||
BlocProvider<SearchResultGoodsListBloc>( | |||||
create: (_) => SearchResultGoodsListBloc(repository: SearchResultGoodsListRepository(reqData: data)), | |||||
), | |||||
], | |||||
child: SearchResultItemPageContianer(), | |||||
), | |||||
); | |||||
} | |||||
} | |||||
class SearchResultItemPageContianer extends StatefulWidget { | |||||
@override | |||||
_SearchResultItemPageContianerState createState() => _SearchResultItemPageContianerState(); | |||||
} | |||||
class _SearchResultItemPageContianerState extends State<SearchResultItemPageContianer> with AutomaticKeepAliveClientMixin { | |||||
@override | |||||
bool get wantKeepAlive => true; | |||||
RefreshController _refreshController; | |||||
ScrollController _controller; | |||||
bool _isEnded = false; | |||||
@override | |||||
void initState() { | |||||
_refreshController = RefreshController(); | |||||
_controller = ScrollController(); | |||||
_controller.addListener(() { | |||||
// print('${_controller.offset} ${_controller.position.maxScrollExtent}'); | |||||
if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { | |||||
// 滑动到底部 | |||||
_isEnded = true; | |||||
Provider.of<SearchResultItemPageNotifier>(context, listen: false).loadMore(); | |||||
} else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { | |||||
_isEnded = false; | |||||
Provider.of<SearchResultItemPageNotifier>(context, listen: false).reset(); | |||||
} | |||||
}); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_refreshController?.dispose(); | |||||
_controller?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocConsumer<SearchResultItemBloc, SearchResultItemState>( | |||||
listener: (BuildContext context, SearchResultItemState state) { | |||||
if (state is SearchResultItemErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchResultItemErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
print('currente state = $state'); | |||||
if (state is SearchResultItemLoadedState) { | |||||
return _getMainWidget(state?.model ?? null); | |||||
} | |||||
/// 骨架屏幕 | |||||
return _getMainWidget(null); | |||||
}, | |||||
); | |||||
} | |||||
/// 上拉更多 | |||||
void _onLoading() async { | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListOnLoadEvent()); | |||||
_refreshController.loadComplete(); | |||||
} | |||||
/// 下拉刷新 | |||||
void _onRefresh() async { | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListOnRefreshEvent()); | |||||
_refreshController.refreshCompleted(resetFooterState: true); | |||||
} | |||||
/// 获取主视图 | |||||
Widget _getMainWidget(List<Map<String, dynamic>> datas) { | |||||
return Scaffold( | |||||
backgroundColor: HexColor.fromHex('#F9F9F9'), | |||||
body: Stack( | |||||
children: <Widget>[ | |||||
Positioned( | |||||
top: 20, | |||||
left: 0, | |||||
right: 0, | |||||
bottom: 0, | |||||
child: SmartRefresher( | |||||
onLoading: _onLoading, | |||||
onRefresh: _onRefresh, | |||||
enablePullDown: true, | |||||
enablePullUp: true, | |||||
// footer: ClassicFooter(), | |||||
// header: WaterDropHeader(), | |||||
controller: _refreshController, | |||||
child: CustomScrollView( | |||||
controller: _controller, | |||||
slivers: _createContentWidget(datas), | |||||
), | |||||
), | |||||
), | |||||
/// 筛选栏 | |||||
_getSearchResultSortWidget(datas), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 筛选栏 | |||||
Widget _getSearchResultSortWidget(List<Map<String, dynamic>> datas) { | |||||
int length = datas?.length ?? 0; | |||||
if (length == 0) { | |||||
return Container(); | |||||
} else { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[0])); | |||||
List<Widget> itemWidgets = WidgetFactory.create(item.modName, isSliver: false, model: datas[0]); | |||||
int length = itemWidgets?.length ?? 0; | |||||
return Align(alignment: Alignment.topCenter, child: length > 0 ? itemWidgets[0] : Container()); | |||||
} | |||||
} | |||||
/// 创建Widget | |||||
List<Widget> _createContentWidget(List<Map<String, dynamic>> datas) { | |||||
List<Widget> list = []; | |||||
int length = datas?.length ?? 0; | |||||
if (length > 0) { | |||||
/// 去除筛选栏, 从1开始 | |||||
for (int i = 1; i < datas.length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: true, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
} else { | |||||
list.add(SliverToBoxAdapter( | |||||
/// TODO 改成骨架图 | |||||
child: HomeGoodsSkeleton(), | |||||
)); | |||||
} | |||||
return list; | |||||
} | |||||
} |
@@ -0,0 +1,109 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/bloc/search_result_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'bloc/search_result_repository.dart'; | |||||
/// | |||||
/// 搜索结果页面 | |||||
/// | |||||
class SearchResultPage extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
const SearchResultPage(this.data); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
// return BlocProvider<SearchResultBloc>( | |||||
// create: (_) => SearchResultBloc(repository: SearchResultRepository())..add(SearchResultInitEvent(model: data)), | |||||
// child: SearchResultContianer(), | |||||
// ); | |||||
return MultiBlocProvider( | |||||
providers: [ | |||||
/// 页面的数据 | |||||
BlocProvider<SearchResultBloc>( | |||||
create: (_) => SearchResultBloc(repository: SearchResultRepository())..add(SearchResultInitEvent(model: data)), | |||||
), | |||||
/// 输入框联想的bloc | |||||
BlocProvider<SearchThinkBloc>( | |||||
create: (_)=> SearchThinkBloc(SearchThinkRepository()), | |||||
), | |||||
], | |||||
child: SearchResultContianer(), | |||||
); | |||||
} | |||||
} | |||||
class SearchResultContianer extends StatefulWidget { | |||||
@override | |||||
_SearchResultContianerState createState() => _SearchResultContianerState(); | |||||
} | |||||
class _SearchResultContianerState extends State<SearchResultContianer> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocConsumer<SearchResultBloc, SearchResultState>( | |||||
listener: (BuildContext context, SearchResultState state) { | |||||
if (state is SearchResultErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchResultErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
print('currente state = $state'); | |||||
if (state is SearchResultLoadedState) { | |||||
return _getMainWidget(state?.model); | |||||
} | |||||
/// 骨架屏幕 | |||||
return _getMainWidget(null); | |||||
}, | |||||
); | |||||
} | |||||
/// 获取主视图 | |||||
Widget _getMainWidget(List<Map<String, dynamic>> data) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Column( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
children: _createContentWidget(data), | |||||
), | |||||
); | |||||
} | |||||
/// 创建视图 | |||||
List<Widget> _createContentWidget(List<Map<String, dynamic>> datas) { | |||||
int length = datas?.length ?? 0; | |||||
List<Widget> list = []; | |||||
if (length > 0) { | |||||
for (int i = 0; i < length; i++) { | |||||
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i])); | |||||
print('item.modName ${item.modName}'); | |||||
list.addAll(WidgetFactory.create( | |||||
item.modName, | |||||
isSliver: false, | |||||
model: datas[i], | |||||
)); | |||||
} | |||||
} else { | |||||
list.add(Container()); | |||||
} | |||||
return list; | |||||
} | |||||
} |
@@ -0,0 +1,61 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:equatable/equatable.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_repository.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/model/search_think_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
part 'search_think_event.dart'; | |||||
part 'search_think_state.dart'; | |||||
class SearchThinkBloc extends Bloc<SearchThinkEvent, SearchThinkState> { | |||||
// SearchThinkBloc() : super(SearchThinkInitial()); | |||||
@override | |||||
SearchThinkState get initialState => SearchThinkInitial(); | |||||
SearchThinkRepository repository; | |||||
SearchThinkBloc(this.repository); | |||||
@override | |||||
Stream<SearchThinkState> mapEventToState(SearchThinkEvent event,) async* { | |||||
/// 关键字改变的方法 | |||||
if (event is SearchThinkKeyWrodsChangeEvent) { | |||||
yield* _mapKeyWordsChangeToState(event); | |||||
} | |||||
/// 修改渠道关键字 | |||||
if (event is SearchThinkChangeTypeEvent) { | |||||
_mapChangeTypeToState(event); | |||||
} | |||||
/// 显示原本的视图 | |||||
if (event is SearchThinkShowBaseViewEvent) { | |||||
yield* _mapShowBaseViewEventToState(); | |||||
} | |||||
} | |||||
/// 关键字改变的方法 | |||||
Stream<SearchThinkState> _mapKeyWordsChangeToState(SearchThinkKeyWrodsChangeEvent event) async* { | |||||
var result = await repository.fetchkeyWordsChange(event.keywords); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchThinkLoadedState(result); | |||||
} else { | |||||
yield SearchThinkErrorState(); | |||||
} | |||||
} | |||||
/// 显示原本的视图 | |||||
Stream<SearchThinkState> _mapShowBaseViewEventToState() async* { | |||||
yield SearchThinkShowBaseViewStatte(); | |||||
} | |||||
/// 修改商品电商类型 | |||||
_mapChangeTypeToState(SearchThinkChangeTypeEvent event) { | |||||
repository.changeType(event.type); | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
part of 'search_think_bloc.dart'; | |||||
abstract class SearchThinkEvent extends Equatable { | |||||
const SearchThinkEvent(); | |||||
} | |||||
/// 数据加载 | |||||
class SearchThinkKeyWrodsChangeEvent extends SearchThinkEvent { | |||||
final String keywords; | |||||
const SearchThinkKeyWrodsChangeEvent(this.keywords, ); | |||||
@override | |||||
List<Object> get props => [this.keywords]; | |||||
} | |||||
/// 修改电商类型 | |||||
class SearchThinkChangeTypeEvent extends SearchThinkEvent{ | |||||
final String type; | |||||
SearchThinkChangeTypeEvent(this.type); | |||||
@override | |||||
List<Object> get props => [this.props]; | |||||
} | |||||
/// 显示原本视图 | |||||
class SearchThinkShowBaseViewEvent extends SearchThinkEvent{ | |||||
@override | |||||
List<Object> get props => []; | |||||
} |
@@ -0,0 +1,35 @@ | |||||
import 'package:zhiying_base_widget/pages/search_think_page/model/search_think_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchThinkRepository { | |||||
// 商品电商渠道类型,默认为淘宝 | |||||
String type = 'taobao'; | |||||
/// 关键字改变 | |||||
Future<List<SearchThinkModel>> fetchkeyWordsChange(String keywrods) async { | |||||
if (!EmptyUtil.isEmpty(keywrods)) { | |||||
var result = await NetUtil.post('/api/v1/s/t/$keywrods', method: NetMethod.GET); | |||||
try { | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
List<String> data = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||||
List<SearchThinkModel> newDatas = []; | |||||
data.forEach((item){ | |||||
newDatas.add(SearchThinkModel(type: type, keywords: item)); | |||||
}); | |||||
return newDatas; | |||||
} | |||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
/// 修改渠道类型 | |||||
void changeType(String newType){ | |||||
this.type = newType; | |||||
print('change type = $type'); | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
part of 'search_think_bloc.dart'; | |||||
abstract class SearchThinkState extends Equatable { | |||||
const SearchThinkState(); | |||||
} | |||||
class SearchThinkInitial extends SearchThinkState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 数据加载完毕 | |||||
class SearchThinkLoadedState extends SearchThinkState{ | |||||
List<SearchThinkModel> model; | |||||
SearchThinkLoadedState(this.model); | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 显示本来的视图 | |||||
class SearchThinkShowBaseViewStatte extends SearchThinkState{ | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 数据加载出错 | |||||
class SearchThinkErrorState extends SearchThinkState{ | |||||
@override | |||||
List<Object> get props => []; | |||||
} |
@@ -0,0 +1,20 @@ | |||||
class SearchThinkModel { | |||||
String type; | |||||
String keywords; | |||||
SearchThinkModel({this.type, this.keywords}); | |||||
factory SearchThinkModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchThinkModel( | |||||
type: json['type'], | |||||
keywords: json['keywords'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['type'] = this.type; | |||||
data['keywords'] = this.keywords; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,147 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'dart:ui'; | |||||
/// | |||||
/// 搜索联想页面 | |||||
/// | |||||
class SearchThinkPage extends StatefulWidget { | |||||
String keywords; | |||||
final Map<String, dynamic> data; | |||||
SearchThinkPage(this.data, {Key key}) : super(key: key) { | |||||
try {} catch (_) {} | |||||
} | |||||
@override | |||||
_SearchThinkPageState createState() => _SearchThinkPageState(); | |||||
} | |||||
class _SearchThinkPageState extends State<SearchThinkPage> { | |||||
TextEditingController _textEditingController; | |||||
FocusNode _focusNode; | |||||
TabController _tabController; | |||||
/// 打开搜索结果 | |||||
void _openSearchResult(String keywords) {} | |||||
/// 关闭当前页面 | |||||
void _closePage() { | |||||
Navigator.maybePop(context); | |||||
} | |||||
/// 点击联想结果页面 | |||||
void _onClickThinkResult(String keywords) {} | |||||
@override | |||||
void initState() { | |||||
_textEditingController = TextEditingController(text: widget?.keywords); | |||||
_focusNode = FocusNode(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_textEditingController?.dispose(); | |||||
_focusNode?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Container( | |||||
margin: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top + 7.5), | |||||
color: HexColor.fromHex('#FFFFFF'), | |||||
width: double.infinity, | |||||
child: Column( | |||||
children: <Widget>[ | |||||
/// 标题 | |||||
_buildTitleWidget(), | |||||
/// 联想结果 | |||||
Expanded( | |||||
child: _buildThinkWidget(null), | |||||
) | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 联想结果 | |||||
Widget _buildThinkWidget(List datas) { | |||||
int length = datas?.length ?? 0; | |||||
return Visibility( | |||||
visible: length > 0, | |||||
child: ListView.builder( | |||||
itemBuilder: (context, item) { | |||||
return Container( | |||||
padding: const EdgeInsets.symmetric(vertical: 13), | |||||
child: Text('', style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 14)), | |||||
); | |||||
}, | |||||
itemCount: length, | |||||
), | |||||
); | |||||
} | |||||
/// titile | |||||
Widget _buildTitleWidget() { | |||||
return Container( | |||||
height: 32, | |||||
width: double.infinity, | |||||
child: Row( | |||||
children: <Widget>[ | |||||
/// 输入框 | |||||
Expanded( | |||||
child: _buildInputWidget(), | |||||
), | |||||
/// 取消按钮 | |||||
_buildButtomWidget(), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 取消按钮 | |||||
Widget _buildButtomWidget() { | |||||
return GestureDetector( | |||||
onTap: () => _closePage(), | |||||
child: Container( | |||||
padding: const EdgeInsets.only(right: 12.5, left: 10, bottom: 6, top: 6), | |||||
child: Text('取消', style: TextStyle(fontSize: 14, color: HexColor.fromHex('#999999'))), | |||||
), | |||||
); | |||||
} | |||||
/// 输入框 | |||||
Widget _buildInputWidget() { | |||||
return Container( | |||||
height: 32, | |||||
margin: const EdgeInsets.only(left: 12.5), | |||||
decoration: BoxDecoration( | |||||
color: HexColor.fromHex('#F9F9F9'), | |||||
borderRadius: BorderRadius.circular(30), | |||||
), | |||||
child: TextField( | |||||
controller: _textEditingController, | |||||
focusNode: _focusNode, | |||||
style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 13, textBaseline: TextBaseline.alphabetic), | |||||
decoration: InputDecoration( | |||||
contentPadding: EdgeInsets.only(left: 12.5, right: 12.5, bottom: 12), | |||||
fillColor: Colors.transparent, | |||||
filled: true, | |||||
border: InputBorder.none, | |||||
errorBorder: InputBorder.none, | |||||
enabledBorder: InputBorder.none, | |||||
disabledBorder: InputBorder.none, | |||||
focusedErrorBorder: InputBorder.none, | |||||
focusedBorder: InputBorder.none, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -4,10 +4,20 @@ import 'package:provider/provider.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | import 'package:pull_to_refresh/pull_to_refresh.dart'; | ||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart'; | ||||
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; | import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart'; | ||||
import 'package:zhiying_base_widget/utils/contants.dart'; | |||||
import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart'; | import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||||
import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart'; | |||||
import 'wallet_page_bloc.dart'; | |||||
import 'wallet_page_bloc.dart'; | |||||
class WalletPage extends StatefulWidget { | class WalletPage extends StatefulWidget { | ||||
final Map<String, dynamic> data; | |||||
const WalletPage({Key key, this.data}) : super(key: key); | |||||
@override | @override | ||||
_WalletPageState createState() => _WalletPageState(); | _WalletPageState createState() => _WalletPageState(); | ||||
} | } | ||||
@@ -22,14 +32,19 @@ class _WalletPageState extends State<WalletPage> { | |||||
ChangeNotifierProvider.value(value: MainPageNotifier()), | ChangeNotifierProvider.value(value: MainPageNotifier()), | ||||
ChangeNotifierProvider.value(value: MainPageBgNotifier()), | ChangeNotifierProvider.value(value: MainPageBgNotifier()), | ||||
], | ], | ||||
child: _WalletPageContainer(), | |||||
child: BlocProvider<WalletPageBloc>( | |||||
bloc: WalletPageBloc(), | |||||
child: _WalletPageContainer(data: widget.data), | |||||
), | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
class _WalletPageContainer extends StatefulWidget { | class _WalletPageContainer extends StatefulWidget { | ||||
_WalletPageContainer({Key key}) : super(key: key); | |||||
_WalletPageContainer({Key key, this.data}) : super(key: key); | |||||
final Map<String, dynamic> data; | |||||
@override | @override | ||||
_WalletPageContainerState createState() => _WalletPageContainerState(); | _WalletPageContainerState createState() => _WalletPageContainerState(); | ||||
@@ -40,8 +55,14 @@ class _WalletPageContainerState extends State<_WalletPageContainer> { | |||||
final RefreshController _refreshController = | final RefreshController _refreshController = | ||||
RefreshController(initialRefresh: false); | RefreshController(initialRefresh: false); | ||||
WalletPageBloc _pageBloc; | |||||
@override | @override | ||||
void initState() { | void initState() { | ||||
_pageBloc = BlocProvider.of<WalletPageBloc>(context); | |||||
if (widget.data.containsKey(Constants.SkipIdentifierName)) { | |||||
_pageBloc.loadData(widget.data[Constants.SkipIdentifierName]); | |||||
} | |||||
super.initState(); | super.initState(); | ||||
} | } | ||||
@@ -53,6 +74,7 @@ class _WalletPageContainerState extends State<_WalletPageContainer> { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
ScreenUtil.init(context, width: 750, height: 1334); | |||||
return SmartRefresher( | return SmartRefresher( | ||||
controller: _refreshController, | controller: _refreshController, | ||||
enablePullDown: false, | enablePullDown: false, | ||||
@@ -67,39 +89,87 @@ class _WalletPageContainerState extends State<_WalletPageContainer> { | |||||
MineHeaderBgWidget( | MineHeaderBgWidget( | ||||
controller: _controller, | controller: _controller, | ||||
), | ), | ||||
CustomScrollView( | |||||
slivers: _createContent(context), | |||||
), | |||||
StreamBuilder( | |||||
stream: _pageBloc.outData, | |||||
builder: (context, asyncSnapshot) { | |||||
var model = asyncSnapshot.data; | |||||
return CustomScrollView( | |||||
slivers: _createContent(context, model), | |||||
); | |||||
}, | |||||
) | |||||
], | ], | ||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
List<Widget> _createContent(BuildContext context) { | |||||
List<Widget> _createContent( | |||||
BuildContext context, List<Map<String, dynamic>> model) { | |||||
List<Widget> list = List(); | List<Widget> list = List(); | ||||
if (model == null) { | |||||
list.addAll(WidgetFactory.create( | |||||
'normal_nav', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_data', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_detail', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'normal_nav', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_data', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_detail', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_income', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
list.addAll(WidgetFactory.create( | |||||
'wallet_income', | |||||
isSliver: true, | |||||
model: Map(), | |||||
)); | |||||
} else { | |||||
for (var item in model) { | |||||
WidgetModel widgetModel = | |||||
WidgetModel.fromJson(Map<String, dynamic>.from(item)); | |||||
if (item.containsKey("mod_name")&&item['mod_name']=="my_wallet_appbar") { | |||||
list.add(SliverPersistentHeader( | |||||
delegate: _SilverAppBarDelegate(context, | |||||
WidgetFactory.create(widgetModel.modName, | |||||
isSliver: false, model: item)[0]),pinned: true,)); | |||||
continue; | |||||
} | |||||
list.addAll(WidgetFactory.create(widgetModel.modName, | |||||
isSliver: true, model: item)); | |||||
} | |||||
} | |||||
return list; | return list; | ||||
} | } | ||||
} | } | ||||
class _SilverAppBarDelegate extends SliverPersistentHeaderDelegate { | |||||
_SilverAppBarDelegate(BuildContext context,this.child){ | |||||
this.context=context; | |||||
} | |||||
BuildContext context; | |||||
final Widget child; | |||||
@override | |||||
double get minExtent => MediaQuery.of(context).padding.top+44; | |||||
@override | |||||
double get maxExtent => MediaQuery.of(context).padding.top+44; | |||||
@override | |||||
Widget build( | |||||
BuildContext context, double shrinkOffset, bool overlapsContent) { | |||||
return child; | |||||
} | |||||
@override | |||||
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) { | |||||
return false; | |||||
} | |||||
} |
@@ -17,13 +17,23 @@ class WalletPageBloc extends BlocBase { | |||||
_tabController = null; | _tabController = null; | ||||
} | } | ||||
void refresh() { | |||||
NetUtil.request('/api/v1/config.json', onSuccess: (data) { | |||||
List list = data; | |||||
_tabs = list.map((item) { | |||||
return Map<String, dynamic>.from(item); | |||||
}).toList(); | |||||
_tabController.add(_tabs); | |||||
loadData(String skipIdentifier) { | |||||
NetUtil.request('/api/v1/mod/${skipIdentifier}', method: NetMethod.GET, | |||||
onCache: (data) { | |||||
_loadData(data); | |||||
}, onSuccess: (data) { | |||||
_loadData(data); | |||||
}); | }); | ||||
} | } | ||||
void refresh() {} | |||||
///处理加载的数据 | |||||
void _loadData(data) { | |||||
print(data["mod_lis"]); | |||||
var list = List.from(data["mod_list"]).map((v) { | |||||
return Map<String, dynamic>.from(v); | |||||
}).toList(); | |||||
_tabController.add(list); | |||||
} | |||||
} | } |
@@ -1,17 +1,22 @@ | |||||
import 'package:sharesdk_plugin/sharesdk_plugin.dart'; | import 'package:sharesdk_plugin/sharesdk_plugin.dart'; | ||||
import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/favorite_page/favorite_page.dart'; | import 'package:zhiying_base_widget/pages/favorite_page/favorite_page.dart'; | ||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/invited_friends/invited_friends.dart'; | import 'package:zhiying_base_widget/pages/invited_friends/invited_friends.dart'; | ||||
import 'package:zhiying_base_widget/pages/launch_page/launch_page.dart'; | import 'package:zhiying_base_widget/pages/launch_page/launch_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/main_page/main_page.dart'; | import 'package:zhiying_base_widget/pages/main_page/main_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/mine_detail_page/mine_detail_page.dart'; | import 'package:zhiying_base_widget/pages/mine_detail_page/mine_detail_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/orders_page/orders_page.dart'; | import 'package:zhiying_base_widget/pages/orders_page/orders_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_page/item/search_item_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/item/search_result_item_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/search_think_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/security_page/security_bind_alipay/security_bind_alipay_page.dart'; | import 'package:zhiying_base_widget/pages/security_page/security_bind_alipay/security_bind_alipay_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/security_page/security_mobile/security_mobile.dart'; | import 'package:zhiying_base_widget/pages/security_page/security_mobile/security_mobile.dart'; | ||||
import 'package:zhiying_base_widget/pages/security_page/security_page.dart'; | import 'package:zhiying_base_widget/pages/security_page/security_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/security_page/security_password/security_password.dart'; | import 'package:zhiying_base_widget/pages/security_page/security_password/security_password.dart'; | ||||
import 'package:zhiying_base_widget/pages/setting_page/setting_page.dart'; | import 'package:zhiying_base_widget/pages/setting_page/setting_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/sreach_result_page/sreach_result_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/search_result_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/wallet_page/wallet_page.dart'; | import 'package:zhiying_base_widget/pages/wallet_page/wallet_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/webview/base_webview.dart'; | import 'package:zhiying_base_widget/pages/webview/base_webview.dart'; | ||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; | ||||
@@ -31,9 +36,13 @@ import 'package:zhiying_base_widget/widgets/mine/mine_nav/mine_nav_bg.dart'; | |||||
import 'package:zhiying_base_widget/widgets/mine/mine_nav/mine_nav_creater.dart'; | import 'package:zhiying_base_widget/widgets/mine/mine_nav/mine_nav_creater.dart'; | ||||
import 'package:zhiying_base_widget/widgets/mine/mine_quick_entry/mine_quick_entry.dart'; | import 'package:zhiying_base_widget/widgets/mine/mine_quick_entry/mine_quick_entry.dart'; | ||||
import 'package:zhiying_base_widget/widgets/others/normal_nav/normal_nav_creater.dart'; | import 'package:zhiying_base_widget/widgets/others/normal_nav/normal_nav_creater.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search_result/sort/search_result_sort_widget.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/tarbar/search_result_tab_creater.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/appbar/search_appbar_creater.dart'; | import 'package:zhiying_base_widget/widgets/search/appbar/search_appbar_creater.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/input/search_input_creater.dart'; | import 'package:zhiying_base_widget/widgets/search/input/search_input_creater.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_creater.dart'; | import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_creater.dart'; | ||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_appbar/wallet_appbar.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_bil/wallet_bil.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_data/wallet_data.dart'; | import 'package:zhiying_base_widget/widgets/wallet/wallet_data/wallet_data.dart'; | ||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/wallet_detail.dart'; | import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/wallet_detail.dart'; | ||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_income/wallet_income.dart'; | import 'package:zhiying_base_widget/widgets/wallet/wallet_income/wallet_income.dart'; | ||||
@@ -47,6 +56,18 @@ import 'widgets/goods_details/evaluate/goods_details_evaluate_widget.dart'; | |||||
import 'widgets/goods_details/recommend/goods_detail_commend_creater.dart'; | import 'widgets/goods_details/recommend/goods_detail_commend_creater.dart'; | ||||
import 'widgets/goods_details/title/goods_details_title_widget.dart'; | import 'widgets/goods_details/title/goods_details_title_widget.dart'; | ||||
import 'widgets/home/home_quick_entry/home_quick_entry.dart'; | import 'widgets/home/home_quick_entry/home_quick_entry.dart'; | ||||
import 'widgets/home/home_sreach/home_sreach_creater.dart'; | |||||
import 'widgets/search/appbar/search_appbar_creater.dart'; | |||||
import 'widgets/search/appbar/search_appbar_widget.dart'; | |||||
import 'widgets/search/history_tag/search_history_tag.dart'; | |||||
import 'widgets/search/hot_tag/search_hot_tag_widget.dart'; | |||||
import 'widgets/search/input/search_input_creater.dart'; | |||||
import 'widgets/search/input/search_input_widget.dart'; | |||||
import 'widgets/search/tabbar/search_tab_creater.dart'; | |||||
import 'widgets/search/tabbar/search_tab_widget.dart'; | |||||
import 'widgets/search_result/goods_list/search_result_goods_list_widget.dart'; | |||||
import 'widgets/search_result/search_input/search_result_input.dart'; | |||||
class BaseWidgetRegister { | class BaseWidgetRegister { | ||||
/// 初始化方法 | /// 初始化方法 | ||||
@@ -79,10 +100,14 @@ class BaseWidgetRegister { | |||||
PageFactory.regist('homePage', (model) => LaunchPage()); | PageFactory.regist('homePage', (model) => LaunchPage()); | ||||
PageFactory.regist('pub.flutter.index', (model) => MainPage(model)); | PageFactory.regist('pub.flutter.index', (model) => MainPage(model)); | ||||
PageFactory.regist('pub.flutter.profile', (model) => MainPage(model)); | PageFactory.regist('pub.flutter.profile', (model) => MainPage(model)); | ||||
PageFactory.regist('pub.flutter.my_wallet', (model) => WalletPage()); | |||||
PageFactory.regist( | |||||
'pub.flutter.my_wallet', (model) => BilDetailPage(model)); | |||||
PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); | PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); | ||||
PageFactory.regist('sreach', (model) => SearchPage(model)); | |||||
PageFactory.regist('sreach_result', (model) => SreachResultPage()); | |||||
PageFactory.regist('search', (model) => SearchPage(model)); | |||||
PageFactory.regist('search_item_page', (model) => SearchItemPage(model)); | |||||
PageFactory.regist('search_result', (model) => SearchResultPage(model)); | |||||
PageFactory.regist('search_result_item', (model) => SearchResultItemPage(model)); | |||||
// PageFactory.regist('search_think_page', (model) => SearchThinkPage(model)); | |||||
// PageFactory.regist('login', (model) => LoginPage(model)); | // PageFactory.regist('login', (model) => LoginPage(model)); | ||||
// PageFactory.regist('login_quick', (model) => LoginQuickPage(model)); | // PageFactory.regist('login_quick', (model) => LoginQuickPage(model)); | ||||
// PageFactory.regist('login_account', (model) => LoginAccountPage(model)); | // PageFactory.regist('login_account', (model) => LoginAccountPage(model)); | ||||
@@ -130,12 +155,10 @@ class BaseWidgetRegister { | |||||
WidgetFactory.regist('index_recommend_list', GoodsListCreater()); | WidgetFactory.regist('index_recommend_list', GoodsListCreater()); | ||||
/// 首页快速入口 | /// 首页快速入口 | ||||
WidgetFactory.regist( | |||||
'multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); | |||||
WidgetFactory.regist('multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model))); | |||||
/// 滚动公告 | /// 滚动公告 | ||||
WidgetFactory.regist('index_placard', | |||||
DefaultWidgetCreater((model) => HomeNoticeWidget(model))); | |||||
WidgetFactory.regist('index_placard', DefaultWidgetCreater((model) => HomeNoticeWidget(model))); | |||||
/// 不可以滚动banner | /// 不可以滚动banner | ||||
WidgetFactory.regist('index_banner_one', HomeBannerCreater()); | WidgetFactory.regist('index_banner_one', HomeBannerCreater()); | ||||
@@ -145,77 +168,102 @@ class BaseWidgetRegister { | |||||
/// ==================== 搜索页面 ==================== /// | /// ==================== 搜索页面 ==================== /// | ||||
// 搜索标题 | // 搜索标题 | ||||
// WidgetFactory.regist('search_index_app_bar', DefaultWidgetCreater((model) => SearchAppbarWidget(model))); | // WidgetFactory.regist('search_index_app_bar', DefaultWidgetCreater((model) => SearchAppbarWidget(model))); | ||||
WidgetFactory.regist('search_index_app_bar', SearchAppbarCreater()); | |||||
// 搜索输入框 | // 搜索输入框 | ||||
WidgetFactory.regist('search_index_input', SearchInputCreater()); | |||||
// WidgetFactory.regist('search_index_input', DefaultWidgetCreater((model) => SearchInputWidget(model))); | |||||
WidgetFactory.regist('search_index_input', DefaultWidgetCreater((model) => SearchInputWidget(model))); | |||||
// // 搜索tabBar | // // 搜索tabBar | ||||
WidgetFactory.regist('search_index_icon_list', SearcchTabCreater()); | WidgetFactory.regist('search_index_icon_list', SearcchTabCreater()); | ||||
// WidgetFactory.regist('search_index_icon_list', DefaultWidgetCreater((model) => SearchTabWidget(model))); | // WidgetFactory.regist('search_index_icon_list', DefaultWidgetCreater((model) => SearchTabWidget(model))); | ||||
// // 热门搜索标签 | // // 热门搜索标签 | ||||
// WidgetFactory.regist('search_index', null); | |||||
WidgetFactory.regist('search_index_host_keyword', DefaultWidgetCreater((model) => SearchHotTagWidget(model))); | |||||
// // 历史搜索标签 | // // 历史搜索标签 | ||||
// WidgetFactory.regist('search_index_history', null); | |||||
WidgetFactory.regist('search_index_history', DefaultWidgetCreater((model) => SearchHistoryTagWidget(model))); | |||||
/// ==================== 搜索结果页面 ==================== /// | |||||
// 输入框 | |||||
WidgetFactory.regist('search_result_input', DefaultWidgetCreater((model) => SearchResultInputWidget(model))); | |||||
// tabbar | |||||
WidgetFactory.regist('search_result_icon_list', SearchResultTabCreater()); | |||||
// 搜索结果页筛选widget 淘宝 | |||||
WidgetFactory.regist('search_result_taobao_sort', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 淘宝 | |||||
WidgetFactory.regist('search_result_taobao_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
// 搜索结果页筛选widget 京东 | |||||
WidgetFactory.regist('search_result_jd_sort', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 京东 | |||||
WidgetFactory.regist('search_result_jd_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
// 搜索结果页筛选widget 苏宁 | |||||
WidgetFactory.regist('search_result_suning_sort', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 苏宁 | |||||
WidgetFactory.regist('search_result_suning_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
// 搜索结果页筛选widget 拼多多 | |||||
WidgetFactory.regist('search_result_pdd_sort', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 拼多多 | |||||
WidgetFactory.regist('search_result_pdd_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
// 搜索结果页筛选widget 唯品会 | |||||
WidgetFactory.regist('search_result_vip', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 唯品会 | |||||
WidgetFactory.regist('search_result_vip_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
// 搜索结果页筛选widget 考拉 | |||||
WidgetFactory.regist('search_result_kaola', DefaultWidgetCreater((model) => SearchResultSortWidget(model))); | |||||
// 搜索结果的商品列表 考拉 | |||||
WidgetFactory.regist('search_result_kaola_item', DefaultWidgetCreater((model) => SearchResultGoodsListWidget(model))); | |||||
/// ==================== 商品详情 ==================== /// | /// ==================== 商品详情 ==================== /// | ||||
// 商品详情轮播图 | // 商品详情轮播图 | ||||
WidgetFactory.regist('product_detail_carousel', | |||||
DefaultWidgetCreater((model) => GoodsDetailsSlideBannerWidget(model))); | |||||
WidgetFactory.regist('product_detail_carousel', DefaultWidgetCreater((model) => GoodsDetailsSlideBannerWidget(model))); | |||||
// 商品详情下载APP提示 | // 商品详情下载APP提示 | ||||
WidgetFactory.regist('product_detail_download_tips', | |||||
DefaultWidgetCreater((model) => UpgradeTipWidget(model))); | |||||
WidgetFactory.regist('product_detail_download_tips', DefaultWidgetCreater((model) => UpgradeTipWidget(model))); | |||||
// 商品详情价格显示 | // 商品详情价格显示 | ||||
WidgetFactory.regist('product_detail_price', | |||||
DefaultWidgetCreater((model) => GoodsDetailsPriceWidget(model))); | |||||
WidgetFactory.regist('product_detail_price', DefaultWidgetCreater((model) => GoodsDetailsPriceWidget(model))); | |||||
// 商品详情标题 | // 商品详情标题 | ||||
WidgetFactory.regist('product_detail_title', | |||||
DefaultWidgetCreater((model) => GoodsDetailsTitleWidget(model))); | |||||
WidgetFactory.regist('product_detail_title', DefaultWidgetCreater((model) => GoodsDetailsTitleWidget(model))); | |||||
// 商品详情优惠劵 | // 商品详情优惠劵 | ||||
WidgetFactory.regist('product_detail_coupon', | |||||
DefaultWidgetCreater((model) => CounponWidget(model))); | |||||
WidgetFactory.regist('product_detail_coupon', DefaultWidgetCreater((model) => CounponWidget(model))); | |||||
// 商品详情店铺 | // 商品详情店铺 | ||||
WidgetFactory.regist('product_detail_shop', | |||||
DefaultWidgetCreater((model) => StoreWidget(model))); | |||||
WidgetFactory.regist('product_detail_shop', DefaultWidgetCreater((model) => StoreWidget(model))); | |||||
// 商品详情宝贝评价 | // 商品详情宝贝评价 | ||||
WidgetFactory.regist('product_detail_comment', | |||||
DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); | |||||
WidgetFactory.regist('product_detail_comment', DefaultWidgetCreater((model) => GoodsDetailsEvaluateWidget(model))); | |||||
// 商品详情图片 | // 商品详情图片 | ||||
WidgetFactory.regist('product_detail_img_list', | |||||
DefaultWidgetCreater((model) => GoodsDetailsImgWidget(model))); | |||||
WidgetFactory.regist('product_detail_img_list', DefaultWidgetCreater((model) => GoodsDetailsImgWidget(model))); | |||||
// 商品详情底部推荐列表 | // 商品详情底部推荐列表 | ||||
WidgetFactory.regist( | |||||
'product_detail_bottom_rec', GoodsDetailCommendCreater()); | |||||
WidgetFactory.regist('product_detail_bottom_rec', GoodsDetailCommendCreater()); | |||||
// 商品详情底部 | // 商品详情底部 | ||||
WidgetFactory.regist('product_detail_bottom', | |||||
DefaultWidgetCreater((model) => GoodsDetailsFooterWidget(model))); | |||||
WidgetFactory.regist('product_detail_bottom', DefaultWidgetCreater((model) => GoodsDetailsFooterWidget(model))); | |||||
// ==================== 个人中心 | // ==================== 个人中心 | ||||
WidgetFactory.regist('profile_appbar', MineNavCreater()); | WidgetFactory.regist('profile_appbar', MineNavCreater()); | ||||
WidgetFactory.regist('profile_background', | |||||
DefaultWidgetCreater((model) => MineNavBg(model))); | |||||
WidgetFactory.regist( | |||||
'profile_header', DefaultWidgetCreater((model) => MineHeader(model))); | |||||
WidgetFactory.regist( | |||||
'profile_earning', DefaultWidgetCreater((model) => MineData(model))); | |||||
WidgetFactory.regist('profile_functions', | |||||
DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||||
WidgetFactory.regist('profile_my_functions', | |||||
DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||||
WidgetFactory.regist('profile_carousel', | |||||
DefaultWidgetCreater((model) => HomeBannerWidget(model))); | |||||
WidgetFactory.regist('profile_background', DefaultWidgetCreater((model) => MineNavBg(model))); | |||||
WidgetFactory.regist('profile_header', DefaultWidgetCreater((model) => MineHeader(model))); | |||||
WidgetFactory.regist('profile_earning', DefaultWidgetCreater((model) => MineData(model))); | |||||
WidgetFactory.regist('profile_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||||
WidgetFactory.regist('profile_my_functions', DefaultWidgetCreater((model) => MineQuickEntry(model))); | |||||
WidgetFactory.regist('profile_carousel', DefaultWidgetCreater((model) => HomeBannerWidget(model))); | |||||
// ==================== 钱包 | // ==================== 钱包 | ||||
WidgetFactory.regist( | WidgetFactory.regist( | ||||
'wallet_data', DefaultWidgetCreater((model) => WalletData())); | |||||
'my_wallet_appbar', | |||||
DefaultWidgetCreater((model) => WalletAppbar( | |||||
data: model, | |||||
))); | |||||
WidgetFactory.regist( | |||||
'my_wallet_header', DefaultWidgetCreater((model) => WalletData(model))); | |||||
WidgetFactory.regist( | |||||
'my_wallet_bil', DefaultWidgetCreater((model) => WalletBil(model))); | |||||
// WidgetFactory.regist( | // WidgetFactory.regist( | ||||
// 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); | // 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); | ||||
// WidgetFactory.regist('wallet_detail', HomeAuthCreater()); | // WidgetFactory.regist('wallet_detail', HomeAuthCreater()); | ||||
WidgetFactory.regist( | |||||
'wallet_data', DefaultWidgetCreater((model) => WalletData())); | |||||
WidgetFactory.regist( | |||||
'wallet_detail', DefaultWidgetCreater((model) => WalletDetail())); | |||||
WidgetFactory.regist('my_wallet_providers', | |||||
DefaultWidgetCreater((model) => WalletDetail(model))); | |||||
WidgetFactory.regist( | WidgetFactory.regist( | ||||
'wallet_income', DefaultWidgetCreater((model) => WalletIncome())); | 'wallet_income', DefaultWidgetCreater((model) => WalletIncome())); | ||||
//======================= 账单明细 | |||||
} | } | ||||
} | } |
@@ -0,0 +1,18 @@ | |||||
import 'package:flutter/material.dart'; | |||||
///通用配置,避免一些多次重复的字符串被写在代码中 | |||||
class Constants { | |||||
///获取模块类型 | |||||
static const String SkipIdentifierName = "skip_identifier"; | |||||
///全局context | |||||
//==============================智能粘贴版===================================start | |||||
static BuildContext context; | |||||
///智能搜索版是否弹起 | |||||
static bool isShowIntellectDialog=false; | |||||
///是否缓存设置信息 | |||||
static String spIsCacheSetModel="spIsCacheSetModel"; | |||||
//==============================智能粘贴版===================================end | |||||
} |
@@ -24,8 +24,9 @@ class GoodsDetailsImgRepository { | |||||
try { | try { | ||||
if(!EmptyUtil.isEmpty(_model)) { | if(!EmptyUtil.isEmpty(_model)) { | ||||
List<String> imgs = await TaobaoLoader.loadImages(_model.good_id); | List<String> imgs = await TaobaoLoader.loadImages(_model.good_id); | ||||
_model.image_detail_list = imgs; | |||||
return _model; | |||||
if(!EmptyUtil.isEmpty(imgs)) { | |||||
return _model.copyWith(_model.image_detail_list + imgs); | |||||
} | |||||
} | } | ||||
}catch(e){ | }catch(e){ | ||||
@@ -26,6 +26,17 @@ class GoodsDetailsImgModel { | |||||
); | ); | ||||
} | } | ||||
GoodsDetailsImgModel copyWith(List<String> newImgs){ | |||||
return GoodsDetailsImgModel( | |||||
image_detail_list: newImgs, | |||||
title: title, | |||||
title_color: title_color, | |||||
provider: provider, | |||||
good_id: good_id, | |||||
icon: icon, | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | Map<String, dynamic> toJson() { | ||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | final Map<String, dynamic> data = new Map<String, dynamic>(); | ||||
data['title'] = this.title; | data['title'] = this.title; | ||||
@@ -40,7 +40,13 @@ class GooddsDetailsFooterContainer extends StatefulWidget { | |||||
class _GooddsDetailsFooterContainerState | class _GooddsDetailsFooterContainerState | ||||
extends State<GooddsDetailsFooterContainer> { | extends State<GooddsDetailsFooterContainer> { | ||||
/// 打开首页 | /// 打开首页 | ||||
void _openHome() {} | |||||
void _openHome() { | |||||
Navigator.pushAndRemoveUntil( | |||||
context, | |||||
MaterialPageRoute(builder: (BuildContext context) => PageFactory.create('homePage', null)), | |||||
(Route<dynamic> route) => false, | |||||
); | |||||
} | |||||
/// 收藏 | /// 收藏 | ||||
void _collectOnClick() {} | void _collectOnClick() {} | ||||
@@ -1,4 +1,6 @@ | |||||
class HomeGoodsModel { | |||||
import 'package:equatable/equatable.dart'; | |||||
class HomeGoodsModel extends Equatable { | |||||
String provider; | String provider; | ||||
String providerName; | String providerName; | ||||
String goodId; | String goodId; | ||||
@@ -53,5 +55,8 @@ class HomeGoodsModel { | |||||
data['inorder_count'] = this.inorderCount; | data['inorder_count'] = this.inorderCount; | ||||
return data; | return data; | ||||
} | } | ||||
@override | |||||
List<Object> get props => [this.goodId, this.provider, this.providerName]; | |||||
} | } | ||||
@@ -100,7 +100,7 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> { | |||||
onTap: (index) => _itemOnClick(datas.index_carousel_list[index]), | onTap: (index) => _itemOnClick(datas.index_carousel_list[index]), | ||||
pagination: _getSwiperStyleByType(datas, datas?.index_carousel_list?.length ?? 0), | pagination: _getSwiperStyleByType(datas, datas?.index_carousel_list?.length ?? 0), | ||||
onIndexChanged: (index) { | onIndexChanged: (index) { | ||||
print('切换下一页'); | |||||
//print('切换下一页'); | |||||
Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container( | Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container( | ||||
width: double.infinity, | width: double.infinity, | ||||
height: 200, | height: 200, | ||||
@@ -1,6 +1,5 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/widgets/home/home_sreach/home_sreach_widget.dart'; | import 'package:zhiying_base_widget/widgets/home/home_sreach/home_sreach_widget.dart'; | ||||
import 'package:zhiying_base_widget/widgets/others/normal_nav/normal_nav.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
class HomeSreachCreater extends WidgetCreater { | class HomeSreachCreater extends WidgetCreater { | ||||
@@ -3,6 +3,7 @@ import 'dart:ui'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | import 'package:cached_network_image/cached_network_image.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_page/search_page.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
class HomeSreachDeleagater extends SliverPersistentHeaderDelegate { | class HomeSreachDeleagater extends SliverPersistentHeaderDelegate { | ||||
@@ -67,6 +68,15 @@ class _HomeSreachContainer extends StatelessWidget { | |||||
const _HomeSreachContainer(this.model); | const _HomeSreachContainer(this.model); | ||||
/// 打开搜索页 | |||||
void _openSreach(BuildContext context){ | |||||
// SkipModel skipModel = SkipModel.fromJson(model); | |||||
// RouterUtil.route(skipModel, null, context); | |||||
Navigator.push(context, MaterialPageRoute( | |||||
builder: (context) => SearchPage(null) | |||||
)); | |||||
} | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
List<Widget> widgets = List(); | List<Widget> widgets = List(); | ||||
@@ -94,10 +104,7 @@ class _HomeSreachContainer extends StatelessWidget { | |||||
widgets.add(Expanded( | widgets.add(Expanded( | ||||
child: GestureDetector( | child: GestureDetector( | ||||
child: _getSreachWidget(), | child: _getSreachWidget(), | ||||
onTap: () { | |||||
SkipModel skipModel = SkipModel.fromJson(model); | |||||
RouterUtil.route(skipModel, null, context); | |||||
}, | |||||
onTap: () => _openSreach(context), | |||||
), | ), | ||||
)); | )); | ||||
@@ -64,7 +64,8 @@ class _MineHeaderContainerState extends State<MineHeaderContainer> { | |||||
), | ), | ||||
), | ), | ||||
onTap: () async { | onTap: () async { | ||||
await RouterUtil.route(SkipModel.fromJson(widget.json), widget.json, context); | |||||
await RouterUtil.route(SkipModel.fromJson(widget.json), | |||||
widget.json, context); | |||||
_bloc.loadData(); | _bloc.loadData(); | ||||
}, | }, | ||||
), | ), | ||||
@@ -1,129 +0,0 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:shared_preferences/shared_preferences.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/text_tag_widget.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/title_widget.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
/// | |||||
/// 历史搜索标签 | |||||
/// | |||||
class HistoryTagWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
const HistoryTagWidget(this.data); | |||||
@override | |||||
_HistoryTagWidgetState createState() => _HistoryTagWidgetState(); | |||||
} | |||||
class _HistoryTagWidgetState extends State<HistoryTagWidget> { | |||||
///文本标签集合 | |||||
List<String> _tagList = []; | |||||
static final String SP_HOISTROY_KEY = 'hoistroyTag'; | |||||
static final int MAX_COUNT = 6; | |||||
/// 点击历史标签 | |||||
void _historyTagClick(String tag) {} | |||||
/// 初始化历史搜索标签 | |||||
_initHistoryTag() async { | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
String jsonStr = prefs.getString(SP_HOISTROY_KEY); | |||||
if (null != jsonStr && jsonStr.length > 0) { | |||||
final Map jsonMap = jsonDecode(jsonStr); | |||||
if (jsonMap != null && jsonMap.length > 0) { | |||||
jsonMap.forEach((key, value) => _tagList.insert(0, value)); | |||||
} | |||||
} | |||||
} | |||||
/// 添加搜索 | |||||
void _addTag(String tag) async { | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
String jsonStr = prefs.getString(SP_HOISTROY_KEY); | |||||
if (null != jsonStr && jsonStr.length > 0) { | |||||
final Map jsonMap = jsonDecode(jsonStr); | |||||
jsonMap[tag.toString()] = tag.toString(); | |||||
_tagList.insert(0, tag); // 第一位 | |||||
if (_tagList.length > MAX_COUNT) { | |||||
jsonMap.remove(_tagList[_tagList.length - 1]); | |||||
_tagList.removeAt(_tagList.length - 1); | |||||
} | |||||
prefs.setString(SP_HOISTROY_KEY, jsonEncode(jsonMap)); | |||||
} else { | |||||
prefs.setString(SP_HOISTROY_KEY, jsonEncode({'${tag.toString()}': '${tag.toString()}'})); | |||||
_tagList.add(tag); | |||||
} | |||||
setState(() {}); | |||||
} | |||||
/// 点击清除所有历史记录 | |||||
void _clearTag() async { | |||||
SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
prefs.setString(SP_HOISTROY_KEY, ''); | |||||
} | |||||
@override | |||||
void initState() { | |||||
_initHistoryTag(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container( | |||||
width: double.infinity, | |||||
margin: const EdgeInsets.only(left: 12.5, right: 12.5), | |||||
child: Column( | |||||
children: <Widget>[ | |||||
/// 标题 | |||||
SearchTitleWidget(titleText: '历史搜索', titleTextColor: '#333333', iconUrl: '', callback: () => _clearTag()), | |||||
const SizedBox( | |||||
height: 10, | |||||
), | |||||
/// 历史标签 | |||||
_getHistoryWarp(), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 历史搜索的标签 | |||||
Widget _getHistoryWarp() { | |||||
List<Widget> itemWidgetList = []; | |||||
final int tagListLength = _tagList?.length ?? 0; | |||||
if (tagListLength > 0) { | |||||
for (var i = 0; i < _tagList.length; i++) { | |||||
var str = _tagList[i]; | |||||
itemWidgetList.add(GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _historyTagClick(_tagList[i]), | |||||
child: TextTagWidget( | |||||
"$str", | |||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), | |||||
margin: const EdgeInsets.only(right: 5, bottom: 0, top: 0), | |||||
borderColor: HexColor.fromHex('#EDEDED'), | |||||
backgroundColor: Colors.white, | |||||
textStyle: TextStyle( | |||||
color: HexColor.fromHex('#383838'), | |||||
fontSize: 12.5, | |||||
), | |||||
), | |||||
)); | |||||
} | |||||
return Wrap( | |||||
spacing: 8.0, | |||||
runSpacing: 8.0, | |||||
///子标签 | |||||
children: itemWidgetList); | |||||
} | |||||
return Container(); | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
class SearchHistoryModel { | |||||
String clear_history_icon; | |||||
String history_bg_color; | |||||
String history_tilte; | |||||
SearchHistoryModel({this.clear_history_icon, this.history_bg_color, this.history_tilte}); | |||||
factory SearchHistoryModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchHistoryModel( | |||||
clear_history_icon: json['clear_history_icon'], | |||||
history_bg_color: json['history_bg_color'], | |||||
history_tilte: json['history_tilte'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['clear_history_icon'] = this.clear_history_icon; | |||||
data['history_bg_color'] = this.history_bg_color; | |||||
data['history_tilte'] = this.history_tilte; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,167 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:shared_preferences/shared_preferences.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/search_result_page.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/history_tag/model/search_history_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/text_tag_widget.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/title_widget.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:provider/provider.dart'; | |||||
/// | |||||
/// 历史搜索标签 | |||||
/// | |||||
class SearchHistoryTagWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
SearchHistoryModel model; | |||||
SearchHistoryTagWidget(this.data, {Key key}) : super(key: key) { | |||||
try { | |||||
model = SearchHistoryModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (e) {} | |||||
} | |||||
@override | |||||
_SearchHistoryTagWidgetState createState() => _SearchHistoryTagWidgetState(); | |||||
} | |||||
class _SearchHistoryTagWidgetState extends State<SearchHistoryTagWidget> { | |||||
///文本标签集合 | |||||
List<String> _tagList = []; | |||||
/// 保存历史标签的sp key | |||||
static final String SP_HOISTROY_KEY = 'hoistroyTag'; | |||||
/// 最大存储条数 | |||||
static final int MAX_COUNT = 10; | |||||
/// 点击历史标签 | |||||
void _historyTagClick(String tag) { | |||||
if (!EmptyUtil.isEmpty(tag)) { | |||||
Navigator.push(context, MaterialPageRoute(builder: (_) => SearchResultPage({'keywords': tag ?? ''}))); | |||||
} | |||||
} | |||||
// /// 初始化历史搜索标签 | |||||
// _initHistoryTag() async { | |||||
// SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
// String jsonStr = prefs.getString(SP_HOISTROY_KEY); | |||||
// if (null != jsonStr && jsonStr.length > 0) { | |||||
// final Map jsonMap = jsonDecode(jsonStr); | |||||
// if (jsonMap != null && jsonMap.length > 0) { | |||||
// jsonMap.forEach((key, value) => _tagList.insert(0, value)); | |||||
// } | |||||
// setState(() {}); | |||||
// } | |||||
// } | |||||
/// 添加搜索 | |||||
// void _addTag(String tag) async { | |||||
// SharedPreferences prefs = await SharedPreferences.getInstance(); | |||||
// String jsonStr = prefs.getString(SP_HOISTROY_KEY); | |||||
// if (null != jsonStr && jsonStr.length > 0) { | |||||
// final Map jsonMap = jsonDecode(jsonStr); | |||||
// jsonMap[tag.toString()] = tag.toString(); | |||||
// | |||||
// _tagList.insert(0, tag); // 第一位 | |||||
// if (_tagList.length > MAX_COUNT) { | |||||
// jsonMap.remove(_tagList[_tagList.length - 1]); | |||||
// _tagList.removeAt(_tagList.length - 1); | |||||
// } | |||||
// | |||||
// prefs.setString(SP_HOISTROY_KEY, jsonEncode(jsonMap)); | |||||
// } else { | |||||
// prefs.setString(SP_HOISTROY_KEY, jsonEncode({'${tag.toString()}': '${tag.toString()}'})); | |||||
// _tagList.add(tag); | |||||
// } | |||||
// setState(() {}); | |||||
// } | |||||
/// 点击清除所有历史记录 | |||||
void _clearTag() async { | |||||
await Provider.of<SearchTagNotifier>(context, listen: false).clear(); | |||||
setState(() { | |||||
}); | |||||
} | |||||
@override | |||||
void initState() { | |||||
_initHistoryTag(); | |||||
super.initState(); | |||||
} | |||||
_initHistoryTag() async { | |||||
_tagList = await Provider.of<SearchTagNotifier>(context, listen: false).getHistoryTag(); | |||||
setState(() { | |||||
}); | |||||
} | |||||
@override | |||||
void didChangeDependencies() { | |||||
_initHistoryTag(); | |||||
super.didChangeDependencies(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container( | |||||
width: double.infinity, | |||||
margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 15), | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
/// 标题 | |||||
SearchTitleWidget( | |||||
titleText: widget?.model?.history_tilte ?? '历史搜索', | |||||
titleTextColor: widget?.model?.history_bg_color ?? '#333333', | |||||
iconUrl: widget?.model?.clear_history_icon ?? '', | |||||
callback: () => _clearTag()), | |||||
const SizedBox( | |||||
height: 10, | |||||
), | |||||
/// 历史标签 | |||||
_getHistoryWarp(), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 历史搜索的标签 | |||||
Widget _getHistoryWarp() { | |||||
List<Widget> itemWidgetList = []; | |||||
final int tagListLength = _tagList?.length ?? 0; | |||||
if (tagListLength > 0) { | |||||
for (var i = 0; i < _tagList.length; i++) { | |||||
var str = _tagList[i]; | |||||
itemWidgetList.add(GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _historyTagClick(_tagList[i]), | |||||
child: TextTagWidget( | |||||
"$str", | |||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), | |||||
margin: const EdgeInsets.only(right: 5, bottom: 0, top: 0), | |||||
borderColor: HexColor.fromHex('#EDEDED'), | |||||
backgroundColor: Colors.white, | |||||
textStyle: TextStyle( | |||||
color: HexColor.fromHex('#383838'), | |||||
fontSize: 12.5, | |||||
), | |||||
), | |||||
)); | |||||
} | |||||
return Wrap( | |||||
spacing: 8.0, | |||||
runSpacing: 8.0, | |||||
///子标签 | |||||
children: itemWidgetList); | |||||
} | |||||
return Container(); | |||||
} | |||||
} |
@@ -0,0 +1,55 @@ | |||||
class SearchHotTagModel { | |||||
String hot_title; | |||||
String hot_title_color; | |||||
List<SearchHostTagItemModel> search_hosts; | |||||
SearchHotTagModel({this.hot_title, this.hot_title_color, this.search_hosts}); | |||||
factory SearchHotTagModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchHotTagModel( | |||||
hot_title: json['hot_title'], | |||||
hot_title_color: json['hot_title_color'], | |||||
search_hosts: json['search_hosts'] != null ? (json['search_hosts'] as List).map((i) => SearchHostTagItemModel.fromJson(i)).toList() : null, | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['hot_title'] = this.hot_title; | |||||
data['hot_title_color'] = this.hot_title_color; | |||||
if (this.search_hosts != null) { | |||||
data['search_hosts'] = this.search_hosts.map((v) => v.toJson()).toList(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class SearchHostTagItemModel { | |||||
String hot_icon; | |||||
String is_hot; | |||||
String keyword; | |||||
String keyword_background_color; | |||||
String keyword_color; | |||||
SearchHostTagItemModel({this.hot_icon, this.is_hot, this.keyword, this.keyword_background_color, this.keyword_color}); | |||||
factory SearchHostTagItemModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchHostTagItemModel( | |||||
hot_icon: json['hot_icon'], | |||||
is_hot: json['is_hot'], | |||||
keyword: json['keyword'], | |||||
keyword_background_color: json['keyword_background_color'], | |||||
keyword_color: json['keyword_color'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['hot_icon'] = this.hot_icon; | |||||
data['is_hot'] = this.is_hot; | |||||
data['keyword'] = this.keyword; | |||||
data['keyword_background_color'] = this.keyword_background_color; | |||||
data['keyword_color'] = this.keyword_color; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,100 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/search_result_page.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/hot_tag/model/search_hot_tag_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/text_tag_widget.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/title_widget.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:provider/provider.dart'; | |||||
/// | |||||
/// 搜索页面,热门搜索的标签 | |||||
/// | |||||
class SearchHotTagWidget extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
SearchHotTagModel model; | |||||
SearchHotTagWidget(this.data, {Key key}) : super(key: key) { | |||||
try { | |||||
model = SearchHotTagModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (e) { | |||||
Logger.error(e); | |||||
} | |||||
} | |||||
/// 点击事件 | |||||
void _tagOnClick(BuildContext context, SearchHostTagItemModel model) async{ | |||||
print('${model?.keyword}'); | |||||
if (!EmptyUtil.isEmpty(model?.keyword)) { | |||||
await Provider.of<SearchTagNotifier>(context, listen: false).addTag(model.keyword); | |||||
Navigator.push(context, MaterialPageRoute(builder: (_) => SearchResultPage({'keywords': model?.keyword ?? ''}))); | |||||
} | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return _getMainWidget(context, model); | |||||
} | |||||
/// 获取主视图 | |||||
Widget _getMainWidget(BuildContext context, SearchHotTagModel model) { | |||||
return Container( | |||||
width: double.infinity, | |||||
margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 15), | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
/// 标题 | |||||
_getTitleWidget(model), | |||||
const SizedBox(height: 13), | |||||
_getTagWidget(context, model), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 标签widget | |||||
Widget _getTagWidget(BuildContext context, SearchHotTagModel model) { | |||||
List<Widget> itemWidgetList = []; | |||||
final int tagListLength = model?.search_hosts?.length ?? 0; | |||||
if (tagListLength > 0) { | |||||
for (var i = 0; i < tagListLength; i++) { | |||||
var item = model.search_hosts[i]; | |||||
itemWidgetList.add(GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _tagOnClick(context, item), | |||||
child: TextTagWidget( | |||||
"${item?.keyword ?? ''}", | |||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), | |||||
margin: const EdgeInsets.only(right: 5, bottom: 0, top: 0), | |||||
borderColor: HexColor.fromHex(item?.keyword_background_color ?? '#FFFFFF'), | |||||
backgroundColor: HexColor.fromHex(item?.keyword_background_color ?? '#FFFFFF'), | |||||
textStyle: TextStyle(color: HexColor.fromHex(item?.keyword_color ?? '#383838'), fontSize: 12), | |||||
icon: item?.hot_icon ?? null, | |||||
), | |||||
)); | |||||
} | |||||
return Wrap( | |||||
spacing: 8.0, | |||||
runSpacing: 8.0, | |||||
///子标签 | |||||
children: itemWidgetList); | |||||
} | |||||
return Container(); | |||||
} | |||||
/// 标题widget | |||||
Widget _getTitleWidget(SearchHotTagModel model) { | |||||
return SearchTitleWidget( | |||||
titleText: model?.hot_title ?? '热门搜索', | |||||
titleTextColor: model?.hot_title_color ?? '#333333', | |||||
); | |||||
} | |||||
} |
@@ -1,11 +1,18 @@ | |||||
import 'dart:convert'; | import 'dart:convert'; | ||||
import 'dart:ui'; | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_result_page/search_result_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/search_think_page.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/input/model/search_input_model.dart'; | import 'package:zhiying_base_widget/widgets/search/input/model/search_input_model.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/input/search_input_sk.dart'; | import 'package:zhiying_base_widget/widgets/search/input/search_input_sk.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:provider/provider.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | import 'package:cached_network_image/cached_network_image.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'package:fluttertoast/fluttertoast.dart'; | |||||
/// | /// | ||||
/// 搜索页的搜索框 | /// 搜索页的搜索框 | ||||
@@ -28,7 +35,35 @@ class SearchInputWidget extends StatefulWidget { | |||||
class _SearchInputWidgetState extends State<SearchInputWidget> { | class _SearchInputWidgetState extends State<SearchInputWidget> { | ||||
/// 点击搜索按钮 | /// 点击搜索按钮 | ||||
void _onSearchButtomClick() {} | |||||
void _onSearchButtomClick() async { | |||||
String content = _editingController?.text?.toString()?.trim() ?? ''; | |||||
/// TODO 保存历史标签 | |||||
if (!EmptyUtil.isEmpty(content)) { | |||||
await Provider.of<SearchTagNotifier>(context, listen: false).addTag(content); | |||||
Navigator.push(context, MaterialPageRoute(builder: (_) => SearchResultPage({'keywords': content}))); | |||||
}else{ | |||||
Fluttertoast.showToast(msg: '输入内容不能为空!'); | |||||
} | |||||
} | |||||
/// 【弃用】打开搜索联想页面 | |||||
void _openSearchThinkPage(){ | |||||
Navigator.push(context, MaterialPageRoute( | |||||
builder: (_)=> SearchThinkPage({}) | |||||
)); | |||||
} | |||||
/// 搜索框值改变 | |||||
void _searchInputChange(String text){ | |||||
if(!EmptyUtil.isEmpty(text)){ | |||||
// 进行网络更新 | |||||
print('输入框的内容是 $text'); | |||||
BlocProvider.of<SearchThinkBloc>(context).add(SearchThinkKeyWrodsChangeEvent(text)); | |||||
}else{ | |||||
/// 输入框为空的时候,隐藏联想视图,显示原本的视图 | |||||
BlocProvider.of<SearchThinkBloc>(context).add(SearchThinkShowBaseViewEvent()); | |||||
} | |||||
} | |||||
FocusNode _focusNode; | FocusNode _focusNode; | ||||
TextEditingController _editingController; | TextEditingController _editingController; | ||||
@@ -65,32 +100,63 @@ class _SearchInputWidgetState extends State<SearchInputWidget> { | |||||
/// 获取主视图 | /// 获取主视图 | ||||
Widget _getMainWidget(SearchInputModel model) { | Widget _getMainWidget(SearchInputModel model) { | ||||
return Container( | return Container( | ||||
color: Colors.white, | |||||
width: double.infinity, | width: double.infinity, | ||||
height: 32, | |||||
margin: const EdgeInsets.only( | |||||
left: 12.5, | |||||
right: 12.5, | |||||
), | |||||
decoration: BoxDecoration( | |||||
borderRadius: BorderRadius.circular(25), | |||||
color: HexColor.fromHex('#F9F9F9'), | |||||
), | |||||
margin: EdgeInsets.only(top: MediaQueryData.fromWindow(window).padding.top + 7.5, left: 12.5, right: 12.5), | |||||
child: Row( | child: Row( | ||||
children: <Widget>[ | children: <Widget>[ | ||||
/// 搜索icon | |||||
_getSearchIconWidget(model), | |||||
const SizedBox(width: 7.5), | |||||
/// 搜索输入框 | |||||
Expanded(child: _getSearchInputWidget(model)), | |||||
/// 搜索按钮 | |||||
_getSearchButtomWidget(model), | |||||
/// 返回键 | |||||
_getReturnWidget(), | |||||
const SizedBox(width: 8.5), | |||||
/// 输入框 | |||||
Expanded( | |||||
child: Container( | |||||
width: double.infinity, | |||||
height: 32, | |||||
// margin: const EdgeInsets.only( | |||||
// left: 12.5, | |||||
// right: 12.5, | |||||
// ), | |||||
decoration: BoxDecoration( | |||||
borderRadius: BorderRadius.circular(25), | |||||
color: HexColor.fromHex('#F9F9F9'), | |||||
), | |||||
child: Row( | |||||
children: <Widget>[ | |||||
/// 搜索icon | |||||
_getSearchIconWidget(model), | |||||
const SizedBox(width: 7.5), | |||||
/// 搜索输入框 | |||||
Expanded(child: _getSearchInputWidget(model)), | |||||
/// 搜索按钮 | |||||
_getSearchButtomWidget(model), | |||||
], | |||||
), | |||||
), | |||||
), | |||||
], | ], | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
/// 返回键 | |||||
Widget _getReturnWidget(){ | |||||
return GestureDetector( | |||||
onTap: ()=> Navigator.maybePop(context), | |||||
child: Container( | |||||
child: Icon( | |||||
Icons.arrow_back_ios, | |||||
size: 22, | |||||
color: HexColor.fromHex('#333333'), | |||||
), | |||||
// onPressed: () => Navigator.maybePop(context), | |||||
), | |||||
); | |||||
} | |||||
/// 搜索icon | /// 搜索icon | ||||
Widget _getSearchIconWidget(SearchInputModel model) { | Widget _getSearchIconWidget(SearchInputModel model) { | ||||
return Container( | return Container( | ||||
@@ -109,10 +175,18 @@ class _SearchInputWidgetState extends State<SearchInputWidget> { | |||||
return Container( | return Container( | ||||
height: double.infinity, | height: double.infinity, | ||||
alignment: Alignment.centerLeft, | alignment: Alignment.centerLeft, | ||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: HexColor.fromHex('#F9F9F9')), | |||||
// padding: const EdgeInsets.symmetric(vertical: 6), | // padding: const EdgeInsets.symmetric(vertical: 6), | ||||
child: TextField( | child: TextField( | ||||
showCursor: true, | showCursor: true, | ||||
// readOnly: true, | |||||
// onTap: ()=> _openSearchThinkPage(), | |||||
onChanged: (val)=> _searchInputChange(val), | |||||
cursorWidth: 1, | cursorWidth: 1, | ||||
onSubmitted: (text) => _onSearchButtomClick(), | |||||
controller: _editingController, | |||||
focusNode: _focusNode, | |||||
cursorColor: Colors.transparent, | |||||
style: TextStyle(fontSize: 14, color: HexColor.fromHex('#333333')), | style: TextStyle(fontSize: 14, color: HexColor.fromHex('#333333')), | ||||
decoration: InputDecoration( | decoration: InputDecoration( | ||||
filled: false, | filled: false, | ||||
@@ -124,7 +198,7 @@ class _SearchInputWidgetState extends State<SearchInputWidget> { | |||||
errorBorder: InputBorder.none, | errorBorder: InputBorder.none, | ||||
disabledBorder: InputBorder.none, | disabledBorder: InputBorder.none, | ||||
enabledBorder: InputBorder.none, | enabledBorder: InputBorder.none, | ||||
hintText: '搜索更多优惠商品', | |||||
hintText: model?.search_inpu_hint_text ?? '搜索更多优惠商品', | |||||
hintStyle: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14), | hintStyle: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14), | ||||
), | ), | ||||
), | ), | ||||
@@ -139,11 +213,14 @@ class _SearchInputWidgetState extends State<SearchInputWidget> { | |||||
child: Container( | child: Container( | ||||
padding: const EdgeInsets.symmetric(horizontal: 17.5, vertical: 6), | padding: const EdgeInsets.symmetric(horizontal: 17.5, vertical: 6), | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
gradient: LinearGradient(colors: [HexColor.fromHex('#FD5E5E'), HexColor.fromHex('#FF0100')], begin: Alignment.centerLeft, end: Alignment.centerRight), | |||||
gradient: LinearGradient( | |||||
colors: [HexColor.fromHex(model?.search_button_color ?? '#FD5E5E'), HexColor.fromHex(model?.search_button_t ?? '#FF0100')], | |||||
begin: Alignment.centerLeft, | |||||
end: Alignment.centerRight), | |||||
borderRadius: BorderRadius.circular(30), | borderRadius: BorderRadius.circular(30), | ||||
), | ), | ||||
child: Text( | child: Text( | ||||
'搜索', | |||||
model?.search_button ?? '搜索', | |||||
style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 14), | style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 14), | ||||
), | ), | ||||
), | ), | ||||
@@ -26,8 +26,18 @@ class SearchTabItemModel { | |||||
String name_select_color; | String name_select_color; | ||||
String type; | String type; | ||||
String with_icon_color; | String with_icon_color; | ||||
String skip_identifier; | |||||
SearchTabItemModel({this.icon, this.line_select_color, this.name, this.name_color, this.name_select_color, this.type, this.with_icon_color}); | |||||
SearchTabItemModel({ | |||||
this.icon, | |||||
this.line_select_color, | |||||
this.name, | |||||
this.name_color, | |||||
this.name_select_color, | |||||
this.type, | |||||
this.with_icon_color, | |||||
this.skip_identifier, | |||||
}); | |||||
factory SearchTabItemModel.fromJson(Map<String, dynamic> json) { | factory SearchTabItemModel.fromJson(Map<String, dynamic> json) { | ||||
return SearchTabItemModel( | return SearchTabItemModel( | ||||
@@ -38,6 +48,7 @@ class SearchTabItemModel { | |||||
name_select_color: json['name_select_color'], | name_select_color: json['name_select_color'], | ||||
type: json['type'], | type: json['type'], | ||||
with_icon_color: json['with_icon_color'], | with_icon_color: json['with_icon_color'], | ||||
skip_identifier: json['skip_identifier'], | |||||
); | ); | ||||
} | } | ||||
@@ -50,6 +61,7 @@ class SearchTabItemModel { | |||||
data['name_select_color'] = this.name_select_color; | data['name_select_color'] = this.name_select_color; | ||||
data['type'] = this.type; | data['type'] = this.type; | ||||
data['with_icon_color'] = this.with_icon_color; | data['with_icon_color'] = this.with_icon_color; | ||||
data['skip_identifier'] = this.skip_identifier; | |||||
return data; | return data; | ||||
} | } | ||||
} | } |
@@ -13,12 +13,12 @@ class SearcchTabCreater extends WidgetCreater{ | |||||
// SearchTabWidget(model), | // SearchTabWidget(model), | ||||
// ), | // ), | ||||
// ), | // ), | ||||
SearchTabWidget(model), | |||||
Expanded(child: SearchTabWidget(model)), | |||||
]; | ]; | ||||
} | } | ||||
@override | @override | ||||
bool isSliverChild() { | bool isSliverChild() { | ||||
return true; | |||||
return false; | |||||
} | } | ||||
} | } |
@@ -3,14 +3,18 @@ import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:cached_network_image/cached_network_image.dart'; | import 'package:cached_network_image/cached_network_image.dart'; | ||||
import 'package:tab_indicator_styler/tab_indicator_styler.dart'; | import 'package:tab_indicator_styler/tab_indicator_styler.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_result_page/search_result_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/model/search_think_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_sk.dart'; | import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_sk.dart'; | ||||
import 'package:zhiying_base_widget/widgets/search/widget/my_tab.dart'; | import 'package:zhiying_base_widget/widgets/search/widget/my_tab.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'model/search_tab_model.dart'; | import 'model/search_tab_model.dart'; | ||||
class SearchTabWidget extends StatefulWidget { | class SearchTabWidget extends StatefulWidget { | ||||
final Map<String, dynamic> data; | final Map<String, dynamic> data; | ||||
SearchTabModel model; | SearchTabModel model; | ||||
@@ -29,12 +33,25 @@ class SearchTabWidget extends StatefulWidget { | |||||
class _SearchTabWidgetState extends State<SearchTabWidget> { | class _SearchTabWidgetState extends State<SearchTabWidget> { | ||||
TabController _tabController; | TabController _tabController; | ||||
int _currentIndex = 0; | |||||
/// 联想列表的item点击事件 | |||||
_onThinkItemClick(SearchThinkModel model){ | |||||
Navigator.push(context, MaterialPageRoute( | |||||
builder: (_)=> SearchResultPage(model.toJson()) | |||||
)); | |||||
} | |||||
@override | @override | ||||
void initState() { | void initState() { | ||||
_tabController = TabController(length: widget?.model?.search_icon_list?.length ?? 0, vsync: ScrollableState())..addListener((){ | _tabController = TabController(length: widget?.model?.search_icon_list?.length ?? 0, vsync: ScrollableState())..addListener((){ | ||||
setState(()=> _currentIndex = _tabController.index); | |||||
String type = ''; | |||||
try{ | |||||
type = widget.model.search_icon_list[_tabController.index].type; | |||||
}catch(_){} | |||||
if(!EmptyUtil.isEmpty(type)) { | |||||
BlocProvider.of<SearchThinkBloc>(context).add(SearchThinkChangeTypeEvent(type)); | |||||
} | |||||
}); | }); | ||||
super.initState(); | super.initState(); | ||||
} | } | ||||
@@ -62,44 +79,110 @@ class _SearchTabWidgetState extends State<SearchTabWidget> { | |||||
/// 获取TabBar | /// 获取TabBar | ||||
Widget _getTabar(SearchTabModel model) { | Widget _getTabar(SearchTabModel model) { | ||||
return Container( | return Container( | ||||
margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 20), | |||||
child: TabBar( | |||||
controller: _tabController, | |||||
isScrollable: true, | |||||
labelStyle: TextStyle( fontSize: 14), | |||||
unselectedLabelColor: HexColor.fromHex('#999999'), | |||||
labelColor: HexColor.fromHex('#FF4242'), | |||||
// indicatorSize: TabBarIndicatorSize.label, | |||||
indicator: MaterialIndicator( | |||||
height: 2.5, | |||||
topLeftRadius: 8, | |||||
topRightRadius: 8, | |||||
bottomLeftRadius: 8, | |||||
bottomRightRadius: 8, | |||||
color: HexColor.fromHex('#FF4242'), | |||||
horizontalPadding: 25, | |||||
), | |||||
tabs: model.search_icon_list.map((item) { | |||||
return MyTab( | |||||
icon: CachedNetworkImage(imageUrl: item?.with_icon_color ?? '', width: 14,), | |||||
text: item.name, | |||||
); | |||||
}).toList(), | |||||
margin: const EdgeInsets.only(/*left: 12.5, right: 12.5,*/ top: 20), | |||||
child: Column( | |||||
children: <Widget>[ | |||||
TabBar( | |||||
controller: _tabController, | |||||
isScrollable: true, | |||||
labelStyle: TextStyle( fontSize: 14, fontWeight: FontWeight.bold), | |||||
unselectedLabelColor: HexColor.fromHex('#999999'), | |||||
labelColor: HexColor.fromHex('#FF4242'), | |||||
// indicatorSize: TabBarIndicatorSize.label, | |||||
indicator: MaterialIndicator( | |||||
height: 2.5, | |||||
topLeftRadius: 8, | |||||
topRightRadius: 8, | |||||
bottomLeftRadius: 8, | |||||
bottomRightRadius: 8, | |||||
color: HexColor.fromHex('#FF4242'), | |||||
horizontalPadding: 25, | |||||
), | |||||
tabs: model.search_icon_list.map((item) { | |||||
return MyTab( | |||||
icon: CachedNetworkImage(imageUrl: item?.with_icon_color ?? '', width: 14,), | |||||
text: item.name, | |||||
); | |||||
}).toList(), | |||||
), | |||||
Expanded( | |||||
child: _getItemWidget(model), | |||||
), | |||||
], | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
} | |||||
/// 根据输入框,是否显示联想列表还是其它 | |||||
Widget _getItemWidget(SearchTabModel model){ | |||||
return Stack( | |||||
children: <Widget>[ | |||||
_getTabBarView(model), | |||||
BlocConsumer<SearchThinkBloc, SearchThinkState>( | |||||
listener: (context, state){}, | |||||
buildWhen: (prev, current){ | |||||
if(current is SearchThinkErrorState){ | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state){ | |||||
// return Visibility( | |||||
// replacement: _getTabBarView(model), | |||||
// | |||||
// child: _getThinkListWidget(), | |||||
// ); | |||||
if(state is SearchThinkLoadedState){ | |||||
return _getThinkListWidget(state.model); | |||||
} | |||||
return Container(); | |||||
}, | |||||
), | |||||
], | |||||
); | |||||
} | |||||
class SearchTabItemWidget extends StatelessWidget { | |||||
final bool isSelect; | |||||
final SearchTabItemModel model; | |||||
/// tabBarView | |||||
Widget _getTabBarView(SearchTabModel model){ | |||||
return TabBarView( | |||||
controller: _tabController, | |||||
children: model.search_icon_list.map((item){ | |||||
// TODO 这里需要和后台沟通改成页面的唯一标示 | |||||
return PageFactory.create('search_item_page', item.toJson()); | |||||
}).toList(), | |||||
); | |||||
} | |||||
const SearchTabItemWidget(this.isSelect, this.model); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container(); | |||||
/// 联想列表 | |||||
Widget _getThinkListWidget(List<SearchThinkModel> model){ | |||||
return Container( | |||||
color: Colors.white, | |||||
height: double.infinity, | |||||
child: ListView.builder(itemBuilder: (context, index){ | |||||
SearchThinkModel item = model[index]; | |||||
return GestureDetector( | |||||
onTap: ()=> _onThinkItemClick(item), | |||||
child: Container( | |||||
decoration: BoxDecoration( | |||||
border: Border(bottom: BorderSide(width: 0.5, color: HexColor.fromHex('#EEEEEE'))) | |||||
), | |||||
padding: const EdgeInsets.only(top: 13, bottom: 13), | |||||
child: Text('${item?.keywords}', style: TextStyle( color: HexColor.fromHex('#333333'), fontSize: 14),), | |||||
), | |||||
); | |||||
}, | |||||
itemCount: model?.length ?? 0, | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5), | |||||
shrinkWrap: true, | |||||
), | |||||
); | |||||
} | } | ||||
} | |||||
} |
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; | |||||
import 'package:flutter/rendering.dart'; | import 'package:flutter/rendering.dart'; | ||||
const double _kTabHeight = 46.0; | const double _kTabHeight = 46.0; | ||||
const double _kTextAndIconTabHeight = 40.0; | |||||
const double _kTextAndIconTabHeight = 35.0; | |||||
/// A material design [TabBar] tab. | /// A material design [TabBar] tab. | ||||
/// | /// | ||||
@@ -1,6 +1,7 @@ | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:zhiying_comm/util/empty_util.dart'; | |||||
import 'color_utils.dart'; | import 'color_utils.dart'; | ||||
/** | /** | ||||
@@ -16,14 +17,13 @@ class TextTagWidget extends StatefulWidget { | |||||
String text; | String text; | ||||
EdgeInsets margin; | EdgeInsets margin; | ||||
EdgeInsets padding; | EdgeInsets padding; | ||||
TextStyle textStyle; | TextStyle textStyle; | ||||
Color backgroundColor; | Color backgroundColor; | ||||
Color borderColor; | Color borderColor; | ||||
double borderRadius; | double borderRadius; | ||||
String icon; | |||||
TextTagWidget( | TextTagWidget( | ||||
this.text, { | this.text, { | ||||
this.margin = const EdgeInsets.all(4), | this.margin = const EdgeInsets.all(4), | ||||
@@ -31,6 +31,7 @@ class TextTagWidget extends StatefulWidget { | |||||
this.textStyle, | this.textStyle, | ||||
this.backgroundColor, | this.backgroundColor, | ||||
this.borderColor, | this.borderColor, | ||||
this.icon, | |||||
this.borderRadius = 20.0, | this.borderRadius = 20.0, | ||||
}) { | }) { | ||||
if (this.borderColor == null) { | if (this.borderColor == null) { | ||||
@@ -62,10 +63,22 @@ class TextTagWidget extends StatefulWidget { | |||||
class _TestPageState extends State<TextTagWidget> { | class _TestPageState extends State<TextTagWidget> { | ||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
if(EmptyUtil.isEmpty(widget.icon)) { | |||||
return buildTag(); | |||||
}else{ | |||||
return buildTag(); | |||||
} | |||||
} | |||||
/// 构建按钮 | |||||
Widget buildTag(){ | |||||
return Container( | return Container( | ||||
margin: widget.margin, | margin: widget.margin, | ||||
padding: widget.padding, | padding: widget.padding, | ||||
decoration: BoxDecoration(color: widget.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)), border: Border.all(color: widget.borderColor)), | |||||
decoration: BoxDecoration( | |||||
color: widget.backgroundColor, borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)), border: Border.all(color: widget.borderColor)), | |||||
child: buildTextWidget(), | child: buildTextWidget(), | ||||
); | ); | ||||
} | } | ||||
@@ -0,0 +1,103 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'package:equatable/equatable.dart'; | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
part 'search_result_goods_list_event.dart'; | |||||
part 'search_result_goods_list_state.dart'; | |||||
class SearchResultGoodsListBloc extends Bloc<SearchResultGoodsListEvent, SearchResultGoodsListState> { | |||||
// SearchResultGoodsListBloc() : super(SearchResultGoodsListInitial()); | |||||
SearchResultGoodsListRepository repository; | |||||
SearchResultGoodsListBloc({@required this.repository}); | |||||
@override | |||||
SearchResultGoodsListState get initialState => SearchResultGoodsListInitial(); | |||||
@override | |||||
Stream<SearchResultGoodsListState> mapEventToState( | |||||
SearchResultGoodsListEvent event, | |||||
) async* { | |||||
/// 初始化 | |||||
if (event is SearchResultGoodsListInitEvent) { | |||||
yield* _mapInitEventToState(event); | |||||
} | |||||
/// 下拉刷新 | |||||
if (event is SearchResultGoodsListOnRefreshEvent) { | |||||
yield* _mapRefreshToState(event); | |||||
} | |||||
/// 上拉更多 | |||||
if (event is SearchResultGoodsListOnLoadEvent && state is SearchResultGoodsListLoadedState) { | |||||
yield* _mapOnLoadToState(event, state); | |||||
} | |||||
/// 修改样式 | |||||
if (event is SearchResultGoodsListChangeStyleEvent) { | |||||
yield* _mapChangeStyleToState(); | |||||
} | |||||
/// 搜索 | |||||
if(event is SearchResultGoodsListSubmitEvent){ | |||||
yield* _mapSubmitToState(event); | |||||
} | |||||
} | |||||
/// 初始化事件 | |||||
Stream<SearchResultGoodsListState> _mapInitEventToState(SearchResultGoodsListInitEvent event) async* { | |||||
var result = await repository.fetchInitData(); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultGoodsListLoadedState(model: result); | |||||
} else { | |||||
yield SearchResultGoodsListErrorState(); | |||||
} | |||||
} | |||||
/// 下拉刷新 | |||||
Stream<SearchResultGoodsListState> _mapRefreshToState(SearchResultGoodsListOnRefreshEvent event) async* { | |||||
var result = await repository.fetchRefreshData(); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultGoodsListLoadedState(model: result); | |||||
} else { | |||||
yield SearchResultGoodsListErrorState(); | |||||
} | |||||
} | |||||
/// 上拉更多 | |||||
Stream<SearchResultGoodsListState> _mapOnLoadToState(SearchResultGoodsListOnLoadEvent event, SearchResultGoodsListLoadedState state) async* { | |||||
var result = await repository.fetchLoadData(); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultGoodsListLoadedState(model: result); | |||||
} else { | |||||
yield SearchResultGoodsListErrorState(); | |||||
} | |||||
} | |||||
/// 修改样式 | |||||
Stream<SearchResultGoodsListState> _mapChangeStyleToState() async* { | |||||
var result = repository.fetchChangeStyle(); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultGoodsListChangeStyleState(result['style'], result['datas']); | |||||
} else { | |||||
yield SearchResultGoodsListErrorState(); | |||||
} | |||||
} | |||||
/// 关键字搜索 | |||||
Stream<SearchResultGoodsListState> _mapSubmitToState(SearchResultGoodsListSubmitEvent event) async* { | |||||
var result = await repository.fetchSearchSubmit(event.keywords); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield SearchResultGoodsListLoadedState(model: result); | |||||
} else { | |||||
yield SearchResultGoodsListErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,26 @@ | |||||
part of 'search_result_goods_list_bloc.dart'; | |||||
abstract class SearchResultGoodsListEvent extends Equatable { | |||||
const SearchResultGoodsListEvent(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 初始化数据 | |||||
class SearchResultGoodsListInitEvent extends SearchResultGoodsListEvent {} | |||||
/// 下拉刷新 | |||||
class SearchResultGoodsListOnRefreshEvent extends SearchResultGoodsListEvent {} | |||||
/// 上拉更多 | |||||
class SearchResultGoodsListOnLoadEvent extends SearchResultGoodsListEvent {} | |||||
/// 修改样式 | |||||
class SearchResultGoodsListChangeStyleEvent extends SearchResultGoodsListEvent{} | |||||
/// 关键字搜索 | |||||
class SearchResultGoodsListSubmitEvent extends SearchResultGoodsListEvent{ | |||||
final String keywords; | |||||
const SearchResultGoodsListSubmitEvent(this.keywords); | |||||
} |
@@ -0,0 +1,107 @@ | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class SearchResultGoodsListRepository { | |||||
SearchResultGoodsListRepository({@required this.reqData}); | |||||
/// 当前页面 | |||||
int _currentPage = 1; | |||||
/// 最大条数 | |||||
final int MAX = 10; | |||||
/// 是否还有更多数据 | |||||
bool _hasNomore = true; | |||||
/// 数据 | |||||
List<HomeGoodsModel> _oldDatas = []; | |||||
/// 显示样式 | |||||
bool _isShowOneColumn = true; | |||||
/// 查询数据参数 | |||||
Map<String, dynamic> reqData = {}; | |||||
/// 初始化 | |||||
Future<List<HomeGoodsModel>> fetchInitData() async { | |||||
_currentPage = 1; | |||||
_hasNomore = true; | |||||
return _baseInitData(true, reqData); | |||||
} | |||||
/// 下拉刷新 | |||||
Future<List<HomeGoodsModel>> fetchRefreshData() async { | |||||
_currentPage = 1; | |||||
_hasNomore = true; | |||||
return _baseInitData(true,reqData); | |||||
} | |||||
/// 上拉更多 | |||||
Future<List<HomeGoodsModel>> fetchLoadData() async { | |||||
/// 只有更多数据的时候才进行加载 | |||||
if (_hasNomore) { | |||||
return _baseInitData(false, reqData); | |||||
} else { | |||||
return null; | |||||
} | |||||
} | |||||
/// 修改显示样式 | |||||
Map<String, dynamic> fetchChangeStyle() { | |||||
_isShowOneColumn = !_isShowOneColumn; | |||||
return {'style': _isShowOneColumn, 'datas': _oldDatas}; | |||||
} | |||||
/// 输入框修改关键字 | |||||
Future<List<HomeGoodsModel>> fetchSearchSubmit(String keywords) async{ | |||||
if(!EmptyUtil.isEmpty(keywords)) { | |||||
reqData['reqData'] = keywords; | |||||
_currentPage = 1; | |||||
_hasNomore =true; | |||||
return _baseInitData(true, reqData); | |||||
} | |||||
return null; | |||||
} | |||||
/// 查询 | |||||
Future<List<HomeGoodsModel>> _baseInitData(bool refresh,final Map<String, dynamic> model) async { | |||||
String keyword = model['keywords'] ?? ''; | |||||
String type = model['type']; | |||||
if (EmptyUtil.isEmpty(keyword)) return null; | |||||
var result = await NetUtil.post('/api/v1/s/$type', | |||||
params: { | |||||
'keyword': keyword, | |||||
'size': MAX.toString(), | |||||
'p': _currentPage.toString(), | |||||
}, | |||||
method: NetMethod.POST); | |||||
try { | |||||
// search_list | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
List data = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['search_list']); | |||||
if (data.length >= MAX) { | |||||
_hasNomore = true; | |||||
++_currentPage; | |||||
} | |||||
// 下拉刷新需要清理 | |||||
if(refresh){ | |||||
_oldDatas.clear(); | |||||
} | |||||
data.forEach((item) { | |||||
_oldDatas.add(HomeGoodsModel.fromJson(item)); | |||||
}); | |||||
List<HomeGoodsModel> newData = []; | |||||
newData.addAll(_oldDatas); | |||||
return newData; | |||||
} | |||||
} catch (e) { | |||||
Logger.error(e); | |||||
} | |||||
_hasNomore = false; | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,42 @@ | |||||
part of 'search_result_goods_list_bloc.dart'; | |||||
abstract class SearchResultGoodsListState extends Equatable { | |||||
const SearchResultGoodsListState(); | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
class SearchResultGoodsListInitial extends SearchResultGoodsListState { | |||||
@override | |||||
List<Object> get props => []; | |||||
} | |||||
/// 数据加载完毕 | |||||
class SearchResultGoodsListLoadedState extends SearchResultGoodsListState { | |||||
List<HomeGoodsModel> model; | |||||
SearchResultGoodsListLoadedState({@required this.model}); | |||||
SearchResultGoodsListLoadedState copyWith(List<HomeGoodsModel> newData) { | |||||
return SearchResultGoodsListLoadedState(model: newData ?? model); | |||||
} | |||||
@override | |||||
List<Object> get props => [this.model]; | |||||
} | |||||
/// 数据加载出错 | |||||
class SearchResultGoodsListErrorState extends SearchResultGoodsListState {} | |||||
/// 切换样式成功 | |||||
class SearchResultGoodsListChangeStyleState extends SearchResultGoodsListState { | |||||
bool isShowOneColumn = true; | |||||
List<HomeGoodsModel> model; | |||||
SearchResultGoodsListChangeStyleState(this.isShowOneColumn, this.model); | |||||
@override | |||||
List<Object> get props => [this.isShowOneColumn]; | |||||
} |
@@ -1,9 +1,9 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
/// | /// | ||||
/// 搜索结果页面 | |||||
/// 商品列表的骨架图 | |||||
/// | /// | ||||
class SreachResultPage extends StatelessWidget { | |||||
class SearchResultGoodsListSkeleton extends StatelessWidget { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return Container(); | return Container(); |
@@ -0,0 +1,192 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item_single.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/models/home_goods_style_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_goods/skeleton/home_goods_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
class SearchResultGoodsListWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
HomeGoodsStyleModel style; | |||||
SearchResultGoodsListWidget(this.data) { | |||||
try { | |||||
style = HomeGoodsStyleModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (e) {} | |||||
} | |||||
@override | |||||
_SearchResultGoodsListWidgetState createState() => _SearchResultGoodsListWidgetState(); | |||||
} | |||||
class _SearchResultGoodsListWidgetState extends State<SearchResultGoodsListWidget> { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
// return BlocProvider<SearchResultGoodsListBloc>( | |||||
// create: (_) => SearchResultGoodsListBloc(repository: SearchResultGoodsListRepository())..add(SearchResultGoodsListInitEvent(model: widget?.data)), | |||||
// child: SearchResultGoodsListWidgetContainer(), | |||||
// ); | |||||
return SearchResultGoodsListWidgetContainer(widget?.data, widget?.style); | |||||
} | |||||
} | |||||
class SearchResultGoodsListWidgetContainer extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
final HomeGoodsStyleModel style; | |||||
const SearchResultGoodsListWidgetContainer(this.data, this.style); | |||||
@override | |||||
_SearchResultGoodsListWidgetContainerState createState() => _SearchResultGoodsListWidgetContainerState(); | |||||
} | |||||
/// 商品列表 | |||||
class _SearchResultGoodsListWidgetContainerState extends State<SearchResultGoodsListWidgetContainer> { | |||||
/// 显示样式 | |||||
bool _isShowOneColumn = true; | |||||
/// 下拉刷新 | |||||
void _onRefersh() async { | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListOnRefreshEvent()); | |||||
} | |||||
/// 上拉更多 | |||||
void _onLoad() async { | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListOnLoadEvent()); | |||||
} | |||||
/// 跳转商品详情 | |||||
void _openGoodsDetailsPage() { | |||||
Navigator.push(context, MaterialPageRoute(builder: (_) => GoodsDetailsPage(null))); | |||||
} | |||||
@override | |||||
void initState() { | |||||
/// 初始化 | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListInitEvent()); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocConsumer<SearchResultGoodsListBloc, SearchResultGoodsListState>( | |||||
listener: (BuildContext context, SearchResultGoodsListState state) { | |||||
if (state is SearchResultGoodsListErrorState) { | |||||
print('数据加载出错'); | |||||
} | |||||
}, | |||||
buildWhen: (previous, current) { | |||||
/// 数据加载出错不进行build | |||||
if (current is SearchResultGoodsListErrorState) { | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
if (state is SearchResultGoodsListLoadedState) { | |||||
return _getMainWidget(state?.model, widget?.style); | |||||
} | |||||
if (state is SearchResultGoodsListChangeStyleState) { | |||||
_isShowOneColumn = state.isShowOneColumn; | |||||
return _getMainWidget(state?.model, widget?.style); | |||||
} | |||||
/// 骨架屏幕 | |||||
return HomeGoodsSkeleton(); | |||||
}, | |||||
); | |||||
} | |||||
/// 获取主视图 | |||||
Widget _getMainWidget(List<HomeGoodsModel> goods, HomeGoodsStyleModel styleModel) { | |||||
int column = _isShowOneColumn ? 1 : 2; | |||||
return ListView.builder( | |||||
shrinkWrap: true, | |||||
physics: NeverScrollableScrollPhysics(), | |||||
itemCount: goods?.length ?? 0, | |||||
itemBuilder: (context, index) { | |||||
if (column == 1) { | |||||
return HomeGoodsItemSingle( | |||||
goods[index], | |||||
styleModel, | |||||
data: widget.data, | |||||
); | |||||
} else { | |||||
// return Container(color: Colors.red, height: 126,margin: EdgeInsets.all(10),); | |||||
return Padding( | |||||
padding: const EdgeInsets.only(left: 5, right: 5), | |||||
child: Row( | |||||
children: List.generate(column, (c) { | |||||
int i = index * column + c; | |||||
return Expanded( | |||||
child: i < goods.length | |||||
? HomeGoodsItem( | |||||
goods[i], | |||||
styleModel, | |||||
data: widget.data, | |||||
) | |||||
: Container(), | |||||
); | |||||
}).toList(), | |||||
), | |||||
); | |||||
} | |||||
}); | |||||
} | |||||
/// 单列 | |||||
// Widget _getSignleWidget(List<HomeGoodsModel> goods, HomeGoodsStyleModel styleModel) { | |||||
// return ListView.builder( | |||||
// shrinkWrap: true, | |||||
// physics: NeverScrollableScrollPhysics(), | |||||
// itemCount: goods.length, | |||||
// itemBuilder: (context, index) { | |||||
// if (column == 1) { | |||||
// return HomeGoodsItemSingle( | |||||
// goods[index], | |||||
// styleModel, | |||||
// data: widget.data, | |||||
// ); | |||||
// } else { | |||||
// // return Container(color: Colors.red, height: 126,margin: EdgeInsets.all(10),); | |||||
// return Padding( | |||||
// padding: const EdgeInsets.only(left: 5, right: 5), | |||||
// child: Row( | |||||
// children: List.generate(column, (c) { | |||||
// int i = index * column + c; | |||||
// return Expanded( | |||||
// child: i < goods.length | |||||
// ? HomeGoodsItem( | |||||
// goods[i], | |||||
// _style, | |||||
// data: widget.data, | |||||
// ) | |||||
// : Container(), | |||||
// ); | |||||
// }).toList(), | |||||
// ), | |||||
// ); | |||||
// } | |||||
// }); | |||||
// | |||||
// return HomeGoodsItemSingle(model, styleModel); | |||||
// } | |||||
// | |||||
// /// 双列 | |||||
// Widget _getTowWidget(List<HomeGoodsModel> goods, HomeGoodsStyleModel styleModel) { | |||||
// int column = 2; | |||||
// int count = (goods.length / column).ceil(); | |||||
// | |||||
// return Container( | |||||
// child: Text('22222222'), | |||||
// ); | |||||
// } | |||||
} |
@@ -0,0 +1,39 @@ | |||||
class SearchResultInputModel { | |||||
String search_button; | |||||
String search_button_color; | |||||
String search_button_t; | |||||
String search_icon; | |||||
String search_inpu_hint_text; | |||||
String keywords; | |||||
SearchResultInputModel({ | |||||
this.search_button, | |||||
this.search_button_color, | |||||
this.search_button_t, | |||||
this.search_icon, | |||||
this.search_inpu_hint_text, | |||||
this.keywords, | |||||
}); | |||||
factory SearchResultInputModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultInputModel( | |||||
search_button: json['search_button'], | |||||
search_button_color: json['search_button_color'], | |||||
search_button_t: json['search_button_t'], | |||||
search_icon: json['search_icon'], | |||||
search_inpu_hint_text: json['search_inpu_hint_text'], | |||||
keywords: json['keywords'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['search_button'] = this.search_button; | |||||
data['search_button_color'] = this.search_button_color; | |||||
data['search_button_t'] = this.search_button_t; | |||||
data['search_icon'] = this.search_icon; | |||||
data['search_inpu_hint_text'] = this.search_inpu_hint_text; | |||||
data['keywords'] = this.keywords; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,160 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/search_input/model/search_result_input_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'dart:ui'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
/// | |||||
/// 搜索结果页面输入框 | |||||
/// | |||||
class SearchResultInputWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
SearchResultInputModel model; | |||||
SearchResultInputWidget(this.data, {Key key}) : super(key: key) { | |||||
try { | |||||
model = SearchResultInputModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (e) { | |||||
Logger.error(e); | |||||
} | |||||
} | |||||
@override | |||||
_SearchResultInputWidgetState createState() => _SearchResultInputWidgetState(); | |||||
} | |||||
class _SearchResultInputWidgetState extends State<SearchResultInputWidget> { | |||||
TextEditingController _textEditingController; | |||||
FocusNode _focusNode; | |||||
/// 返回事件 | |||||
void _openPop() { | |||||
Navigator.maybePop(context); | |||||
} | |||||
/// 搜索事件 | |||||
void _onSearchButtomClick() { | |||||
print('搜索商品'); | |||||
String keywords = _textEditingController?.text?.toString()?.trim(); | |||||
if(!EmptyUtil.isEmpty(keywords)){ | |||||
// BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListSubmitEvent(keywords)); | |||||
} | |||||
} | |||||
@override | |||||
void initState() { | |||||
_textEditingController = TextEditingController(text: widget?.model?.keywords ?? ''); | |||||
_focusNode = FocusNode(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_focusNode?.unfocus(); | |||||
_focusNode?.dispose(); | |||||
_textEditingController?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container( | |||||
child: _getMainWidget(widget?.model), | |||||
); | |||||
} | |||||
/// 主视图 | |||||
Widget _getMainWidget(SearchResultInputModel model) { | |||||
return Container( | |||||
width: double.infinity, | |||||
margin: EdgeInsets.only(/*left: 12.5,*/ right: 12.5, top: MediaQueryData.fromWindow(window).padding.top), | |||||
// child: _getAppBar(model), | |||||
child: Row( | |||||
children: <Widget>[ | |||||
/// 返回键 | |||||
_createReturnWidget(model), | |||||
/// 输入框 | |||||
Expanded(child: _createInputWidget(model)), | |||||
/// 搜索按钮 | |||||
_createSubmitButtomWidget(model), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
/// 返回按钮 | |||||
Widget _createReturnWidget(SearchResultInputModel model) { | |||||
return IconButton( | |||||
icon: Icon( | |||||
Icons.arrow_back_ios, | |||||
size: 22, | |||||
color: HexColor.fromHex('#000000'), | |||||
), | |||||
onPressed: () => _openPop(), | |||||
); | |||||
} | |||||
/// 搜索按钮 | |||||
Widget _createSubmitButtomWidget(SearchResultInputModel model) { | |||||
return GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: ()=> _onSearchButtomClick(), | |||||
child: Container( | |||||
alignment: Alignment.center, | |||||
padding: const EdgeInsets.only( | |||||
top: 6, | |||||
bottom: 6, | |||||
left: 10, /*right: 12.5*/ | |||||
), | |||||
child: Text( | |||||
model?.search_button ?? '搜索', | |||||
style: TextStyle(fontSize: 14, color: HexColor.fromHex(model?.search_button_color), fontWeight: FontWeight.bold), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 输入框 | |||||
Widget _createInputWidget(SearchResultInputModel model) { | |||||
return Container( | |||||
width: double.infinity, | |||||
child: Container( | |||||
height: 32, | |||||
decoration: BoxDecoration( | |||||
borderRadius: BorderRadius.circular(30), | |||||
color: HexColor.fromHex('#F9F9F9'), | |||||
), | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5), | |||||
child: TextField( | |||||
onTap: ()=> Navigator.maybePop(context, _textEditingController?.text?.toString()?.trim()), | |||||
showCursor: true, | |||||
cursorWidth: 1, | |||||
onSubmitted: (text) => _onSearchButtomClick(), | |||||
controller: _textEditingController, | |||||
focusNode: _focusNode, | |||||
style: TextStyle(fontSize: 14, color: HexColor.fromHex('#333333')), | |||||
decoration: InputDecoration( | |||||
filled: false, | |||||
// focusColor: Colors.transparent, | |||||
// fillColor: Colors.transparent, | |||||
border: InputBorder.none, | |||||
focusedBorder: InputBorder.none, | |||||
focusedErrorBorder: InputBorder.none, | |||||
errorBorder: InputBorder.none, | |||||
disabledBorder: InputBorder.none, | |||||
enabledBorder: InputBorder.none, | |||||
hintText: model?.search_inpu_hint_text ?? '搜索更多优惠商品', | |||||
hintStyle: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14), | |||||
), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,126 @@ | |||||
class SearchResultSortModel { | |||||
String coupin_icon; | |||||
String coupin_icon_with_color; | |||||
String layout_icon_1; | |||||
String layout_icon_2; | |||||
List<SearchResultItemSort> sort_list; | |||||
String text_no_select_color; | |||||
String text_select_color; | |||||
/// 是否展示1列 | |||||
bool isShowOneColumn; | |||||
String keywords; | |||||
SearchResultSortModel({ | |||||
this.coupin_icon, | |||||
this.coupin_icon_with_color, | |||||
this.layout_icon_1, | |||||
this.layout_icon_2, | |||||
this.sort_list, | |||||
this.text_no_select_color, | |||||
this.text_select_color, | |||||
this.isShowOneColumn, | |||||
this.keywords, | |||||
}); | |||||
factory SearchResultSortModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultSortModel( | |||||
coupin_icon: json['coupin_icon'], | |||||
coupin_icon_with_color: json['coupin_icon_with_color'], | |||||
layout_icon_1: json['layout_icon_1'], | |||||
layout_icon_2: json['layout_icon_2'], | |||||
sort_list: json['sort_list'] != null ? (json['sort_list'] as List).map((i) => SearchResultItemSort.fromJson(i)).toList() : null, | |||||
text_no_select_color: json['text_no_select_color'], | |||||
text_select_color: json['text_select_color'], | |||||
isShowOneColumn: json['isShowOneColumn'] ?? false, | |||||
keywords: json['keywords'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['coupin_icon'] = this.coupin_icon; | |||||
data['coupin_icon_with_color'] = this.coupin_icon_with_color; | |||||
data['layout_icon_1'] = this.layout_icon_1; | |||||
data['layout_icon_2'] = this.layout_icon_2; | |||||
data['text_no_select_color'] = this.text_no_select_color; | |||||
data['text_select_color'] = this.text_select_color; | |||||
if (this.sort_list != null) { | |||||
data['sort_list'] = this.sort_list.map((v) => v.toJson()).toList(); | |||||
} | |||||
data['isShowOneColumn'] = this.isShowOneColumn; | |||||
data['keywords'] = this.keywords; | |||||
return data; | |||||
} | |||||
} | |||||
class SearchResultItemSort { | |||||
String name; | |||||
bool isSelect; | |||||
List<SearchResultSortSelect> select_list; | |||||
String type; | |||||
String icon; | |||||
String color_icon; | |||||
String color_icon_up; | |||||
String color_icon_down; | |||||
SearchResultItemSort({ | |||||
this.name, | |||||
this.select_list, | |||||
this.isSelect, | |||||
this.type, | |||||
this.icon, | |||||
this.color_icon, | |||||
this.color_icon_up, | |||||
this.color_icon_down, | |||||
}); | |||||
factory SearchResultItemSort.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultItemSort( | |||||
name: json['name'], | |||||
isSelect: json['isSelect'] ?? false, | |||||
select_list: json['select_list'] != null ? (json['select_list'] as List).map((i) => SearchResultSortSelect.fromJson(i)).toList() : null, | |||||
type: json['type']?.toString(), | |||||
icon: json['icon']?.toString(), | |||||
color_icon: json['color_icon']?.toString(), | |||||
color_icon_up: json['color_icon_up']?.toString(), | |||||
color_icon_down: json['color_icon_down']?.toString(), | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['name'] = this.name; | |||||
data['isSelect'] = this.isSelect; | |||||
if (this.select_list != null) { | |||||
data['select_list'] = this.select_list.map((v) => v.toJson()).toList(); | |||||
} | |||||
data['type'] = this.type; | |||||
data['icon'] = this.icon; | |||||
data['color_icon'] = this.color_icon; | |||||
data['color_icon_up'] = this.color_icon_up; | |||||
data['color_icon_down'] = this.color_icon_down; | |||||
return data; | |||||
} | |||||
} | |||||
class SearchResultSortSelect { | |||||
String name; | |||||
String query_args; | |||||
SearchResultSortSelect({this.name, this.query_args}); | |||||
factory SearchResultSortSelect.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultSortSelect( | |||||
name: json['name'], | |||||
query_args: json['query_args'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['name'] = this.name; | |||||
data['query_args'] = this.query_args; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,384 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/sort/model/search_result_sort_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
/// | |||||
/// 搜索结果页排序widget | |||||
/// | |||||
class SearchResultSortWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
SearchResultSortModel model; | |||||
SearchResultSortWidget(this.data, {Key key}) : super(key: key) { | |||||
try { | |||||
model = SearchResultSortModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (_) {} | |||||
} | |||||
@override | |||||
_SearchResultSortWidgetState createState() => _SearchResultSortWidgetState(); | |||||
} | |||||
class _SearchResultSortWidgetState extends State<SearchResultSortWidget> { | |||||
TextEditingController _startPriceEditingController; | |||||
TextEditingController _endPriceEditingController; | |||||
FocusNode _startPriceNode; | |||||
FocusNode _endPriceNode; | |||||
// 是否展开综合 | |||||
bool _isShowZh = false; | |||||
// 切换显示样式 | |||||
bool _isShowOneColumn = true; | |||||
// 是否展开下拉选项 | |||||
bool _expand = false; | |||||
/// 切换类型 | |||||
void _changeColumn() { | |||||
setState(() => _isShowOneColumn = !_isShowOneColumn); | |||||
BlocProvider.of<SearchResultGoodsListBloc>(context).add(SearchResultGoodsListChangeStyleEvent()); | |||||
} | |||||
/// 张开关闭下拉框 | |||||
void _openXLWidget(){ | |||||
setState(() { | |||||
_expand = !_expand; | |||||
}); | |||||
} | |||||
/// 展开综合 | |||||
void _openZHPopupWidget() {} | |||||
/// 展开筛选 | |||||
void _openSXWidget() {} | |||||
/// 点击当前 | |||||
void _clickSortType(SearchResultItemSort model) { | |||||
if(model.type != 'sort'){ | |||||
setState(() { | |||||
_expand = !_expand; | |||||
}); | |||||
} | |||||
} | |||||
/// 关闭下拉框 | |||||
@override | |||||
void initState() { | |||||
_startPriceEditingController = TextEditingController(); | |||||
_endPriceEditingController = TextEditingController(); | |||||
_startPriceNode = FocusNode(); | |||||
_endPriceNode = FocusNode(); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_startPriceNode?.unfocus(); | |||||
_endPriceNode?.unfocus(); | |||||
_startPriceNode?.dispose(); | |||||
_endPriceNode?.dispose(); | |||||
_startPriceEditingController?.dispose(); | |||||
_endPriceEditingController?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container( | |||||
// height: 41, | |||||
width: double.infinity, | |||||
// color: Colors.red, | |||||
child: _getMainWidget(widget?.model), | |||||
); | |||||
} | |||||
/// 主视图 | |||||
Widget _getMainWidget(SearchResultSortModel model) { | |||||
return Column( | |||||
children: <Widget>[ | |||||
/// 筛选栏 | |||||
Container( | |||||
height: 41, | |||||
width: double.infinity, | |||||
color: Colors.white, | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5), | |||||
child: Row( | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: _createSortListWidget(model), | |||||
), | |||||
), | |||||
/// 切换按钮 | |||||
_getChangeIconWidget(model), | |||||
], | |||||
), | |||||
), | |||||
/// 展开列表 | |||||
Visibility( | |||||
visible: _expand, | |||||
child: Expanded( | |||||
child: GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _openXLWidget(), | |||||
child: Container( | |||||
// height: double.infinity, | |||||
width: double.infinity, | |||||
decoration: BoxDecoration( | |||||
color: HexColor.fromHex('#33333333'), | |||||
), | |||||
child: Visibility( | |||||
visible: _isShowZh, | |||||
replacement: _getZHWidget(model), | |||||
child: _getSXWidget(model), | |||||
), | |||||
), | |||||
), | |||||
), | |||||
) | |||||
], | |||||
); | |||||
} | |||||
/// ExpandedList 展开列表 | |||||
Widget _getZHWidget(SearchResultSortModel data) { | |||||
List<SearchResultSortSelect> model; | |||||
List<Widget> lists = []; | |||||
int sort_list_length = data?.sort_list?.length ?? 0; | |||||
if (sort_list_length > 0) { | |||||
data.sort_list.forEach((item) { | |||||
if (item.type == 'popup') { | |||||
model = item.select_list; | |||||
} | |||||
}); | |||||
for (int i = 0; i < model.length; i++) { | |||||
var item = model[i]; | |||||
double borderRadius = (i == model.length - 1) ? 12.5 : 0; | |||||
var padding = EdgeInsets.only(left: 12.5, right: 12.5, top: 10, bottom: (i == model.length - 1) ? 15 : 0); | |||||
lists.add(Container( | |||||
padding: padding, | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
border: Border.all(width: 0, color: Colors.transparent), | |||||
borderRadius: BorderRadius.only( | |||||
bottomRight: Radius.circular(borderRadius), | |||||
bottomLeft: Radius.circular(borderRadius), | |||||
)), | |||||
width: double.infinity, | |||||
child: Text( | |||||
item?.name ?? '', | |||||
style: TextStyle(fontSize: 12, color: HexColor.fromHex(widget?.model?.text_no_select_color)), | |||||
), | |||||
)); | |||||
} | |||||
} else { | |||||
lists.add(Container( | |||||
height: 1, | |||||
)); | |||||
} | |||||
return Column( | |||||
children: lists, | |||||
); | |||||
} | |||||
/// 获取筛选列表 | |||||
Widget _getSXWidget(SearchResultSortModel data) { | |||||
List<Widget> lists = []; | |||||
List<SearchResultSortSelect> model; | |||||
int sort_list_length = data?.sort_list?.length ?? 0; | |||||
if (sort_list_length > 0) { | |||||
data.sort_list.forEach((item) { | |||||
if (item.type == 'popup-filter') { | |||||
model = item.select_list; | |||||
} | |||||
}); | |||||
int length = model?.length ?? 0; | |||||
if (length > 0) { | |||||
for (int i = 0; i < model.length; i++) { | |||||
if (i == 0) { | |||||
lists.add(Container( | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5, top: 10), | |||||
decoration: BoxDecoration(color: Colors.white, border: Border.all(width: 0, color: Colors.transparent)), | |||||
child: _getPriceBetweenWidget(), | |||||
)); | |||||
} | |||||
if (i == 1) { | |||||
lists.add(Container( | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5, top: 13, bottom: 15), | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
border: Border.all(width: 0, color: Colors.transparent), | |||||
borderRadius: BorderRadius.only( | |||||
bottomLeft: Radius.circular(12.5), | |||||
bottomRight: Radius.circular(12.5), | |||||
)), | |||||
child: _getStoryType())); | |||||
} | |||||
} | |||||
} else { | |||||
lists.add(Container()); | |||||
} | |||||
} else { | |||||
lists.add(Container()); | |||||
} | |||||
return Column(children: lists); | |||||
} | |||||
/// 价格区间 | |||||
Widget _getPriceBetweenWidget() { | |||||
return Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
Text( | |||||
'价格区间(元)', | |||||
style: TextStyle(fontSize: 14, color: HexColor.fromHex('#999999')), | |||||
), | |||||
Row( | |||||
children: <Widget>[ | |||||
/// 最低价格 | |||||
_getCustomTextField(controller: _startPriceEditingController, focusNode: _startPriceNode, hintText: '最低价格', hintTextColor: '#999999'), | |||||
/// 文字 【至】 | |||||
Container(margin: const EdgeInsets.symmetric(horizontal: 8), child: Text('至', style: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14))), | |||||
/// 最高价格 | |||||
_getCustomTextField(controller: _endPriceEditingController, focusNode: _endPriceNode, hintTextColor: '#999999', hintText: '最高价格'), | |||||
], | |||||
), | |||||
], | |||||
); | |||||
} | |||||
/// 只看自营 | |||||
Widget _getStoryType() { | |||||
return Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
Text( | |||||
'商家类型', | |||||
style: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14), | |||||
), | |||||
Container( | |||||
padding: const EdgeInsets.symmetric(horizontal: 21, vertical: 8.5), | |||||
child: Text( | |||||
'只看自营', | |||||
style: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 12), | |||||
), | |||||
decoration: BoxDecoration( | |||||
border: Border.all(color: HexColor.fromHex('#E7E7E7'), width: 0.5), | |||||
borderRadius: BorderRadius.circular(5), | |||||
), | |||||
), | |||||
], | |||||
); | |||||
} | |||||
/// 输入框 | |||||
Widget _getCustomTextField({TextEditingController controller, FocusNode focusNode, String hintText, String hintTextColor, double radius = 5}) { | |||||
return Container( | |||||
width: 90, | |||||
height: 33.5, | |||||
alignment: Alignment.center, | |||||
decoration: BoxDecoration( | |||||
color: HexColor.fromHex('#F5F5F5'), | |||||
borderRadius: BorderRadius.circular(radius), | |||||
), | |||||
child: TextField( | |||||
controller: controller, | |||||
focusNode: focusNode, | |||||
decoration: InputDecoration( | |||||
filled: true, | |||||
fillColor: Colors.transparent, | |||||
border: InputBorder.none, | |||||
focusedBorder: InputBorder.none, | |||||
focusedErrorBorder: InputBorder.none, | |||||
errorBorder: InputBorder.none, | |||||
disabledBorder: InputBorder.none, | |||||
enabledBorder: InputBorder.none, | |||||
hintText: hintText, | |||||
hintStyle: TextStyle(color: HexColor.fromHex(hintTextColor), fontSize: 12)), | |||||
), | |||||
); | |||||
} | |||||
/// 自定义widget | |||||
Widget _getCustomWidget(SearchResultItemSort model) { | |||||
return GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _clickSortType(model), | |||||
child: Container( | |||||
child: Row( | |||||
children: <Widget>[ | |||||
Text(model?.name ?? '综合', | |||||
style: TextStyle( | |||||
color: HexColor.fromHex(model.isSelect ? widget?.model?.text_select_color ?? '#FF4242' : widget?.model?.text_no_select_color ?? '#333333'), fontSize: 14)), | |||||
const SizedBox(width: 4), | |||||
Container( | |||||
width: 12, | |||||
height: 12, | |||||
alignment: Alignment.center, | |||||
color: Colors.white, | |||||
child: CachedNetworkImage( | |||||
imageUrl: model?.icon ?? '', | |||||
width: 12, | |||||
) | |||||
) | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 排序widget | |||||
List<Widget> _createSortListWidget(SearchResultSortModel model) { | |||||
List<Widget> list = []; | |||||
int length = model?.sort_list?.length ?? 0; | |||||
if (length > 0) { | |||||
for (int i = 0; i < model.sort_list.length; i++) { | |||||
SearchResultItemSort item = model.sort_list[i]; | |||||
list.add(_getCustomWidget(item)); | |||||
} | |||||
} | |||||
return list; | |||||
} | |||||
/// 切换icon | |||||
Widget _getChangeIconWidget(SearchResultSortModel model) { | |||||
return GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: () => _changeColumn(), | |||||
child: Container( | |||||
height: 25, | |||||
width: 34, | |||||
margin: const EdgeInsets.only(left: 5), | |||||
padding: const EdgeInsets.only(left: 9), | |||||
decoration: BoxDecoration( | |||||
// color: Colors.yellowAccent, | |||||
border: Border( | |||||
left: BorderSide(color: HexColor.fromHex('#C9C5C5'), width: 0.5), | |||||
)), | |||||
alignment: Alignment.center, | |||||
child: CachedNetworkImage( | |||||
imageUrl: _isShowOneColumn ? model?.layout_icon_2 ?? '' : model?.layout_icon_1 ?? '', | |||||
width: 12, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,73 @@ | |||||
class SearchResultTabModel { | |||||
List<SearchResultTabItemModel> search_icon_list; | |||||
String keywords; | |||||
SearchResultTabModel({ | |||||
this.search_icon_list, | |||||
this.keywords, | |||||
}); | |||||
factory SearchResultTabModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultTabModel( | |||||
search_icon_list: json['search_icon_list'] != null ? (json['search_icon_list'] as List).map((i) => SearchResultTabItemModel.fromJson(i)).toList() : null, | |||||
keywords: json['keywords'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
if (this.search_icon_list != null) { | |||||
data['search_icon_list'] = this.search_icon_list.map((v) => v.toJson()).toList(); | |||||
} | |||||
data['keywords'] = keywords; | |||||
return data; | |||||
} | |||||
} | |||||
class SearchResultTabItemModel { | |||||
String icon; | |||||
String line_select_color; | |||||
String name; | |||||
String name_color; | |||||
String name_select_color; | |||||
String type; | |||||
String with_icon_color; | |||||
String skip_identifier; | |||||
SearchResultTabItemModel({ | |||||
this.icon, | |||||
this.line_select_color, | |||||
this.name, | |||||
this.name_color, | |||||
this.name_select_color, | |||||
this.type, | |||||
this.with_icon_color, | |||||
this.skip_identifier, | |||||
}); | |||||
factory SearchResultTabItemModel.fromJson(Map<String, dynamic> json) { | |||||
return SearchResultTabItemModel( | |||||
icon: json['icon'], | |||||
line_select_color: json['line_select_color'], | |||||
name: json['name'], | |||||
name_color: json['name_color'], | |||||
name_select_color: json['name_select_color'], | |||||
type: json['type'], | |||||
with_icon_color: json['with_icon_color'], | |||||
skip_identifier: json['skip_identifier'], | |||||
); | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['icon'] = this.icon; | |||||
data['line_select_color'] = this.line_select_color; | |||||
data['name'] = this.name; | |||||
data['name_color'] = this.name_color; | |||||
data['name_select_color'] = this.name_select_color; | |||||
data['type'] = this.type; | |||||
data['with_icon_color'] = this.with_icon_color; | |||||
data['skip_identifier'] = this.skip_identifier; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,23 @@ | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'search_result_tab_widget.dart'; | |||||
class SearchResultTabCreater extends WidgetCreater{ | |||||
@override | |||||
List<Widget> createWidgets(Map<String, dynamic> model) { | |||||
return [ | |||||
// SliverPersistentHeader( | |||||
// delegate: SliverTabBarDelegate( | |||||
// SearchTabWidget(model), | |||||
// ), | |||||
// ), | |||||
Expanded( | |||||
child: SearchResultTabWidget(model) | |||||
), | |||||
]; | |||||
} | |||||
} |
@@ -0,0 +1,22 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_comm/util/shimmer_util.dart'; | |||||
class SearchResultTabSkeleton extends StatelessWidget { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container( | |||||
width: double.infinity, | |||||
margin: const EdgeInsets.only(left: 12.5, right: 12.5, top: 20), | |||||
child: Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
ShimmerUtil.getShimmerWidget(width: 45, height: 15), | |||||
ShimmerUtil.getShimmerWidget(width: 45, height: 15), | |||||
ShimmerUtil.getShimmerWidget(width: 45, height: 15), | |||||
ShimmerUtil.getShimmerWidget(width: 45, height: 15), | |||||
ShimmerUtil.getShimmerWidget(width: 45, height: 15), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,163 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:tab_indicator_styler/tab_indicator_styler.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_think_page/model/search_think_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/tabbar/search_tab_sk.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search/widget/my_tab.dart'; | |||||
import 'package:zhiying_base_widget/widgets/search_result/sort/search_result_sort_widget.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'model/search_result_tab_model.dart'; | |||||
class SearchResultTabWidget extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
SearchResultTabModel model; | |||||
SearchResultTabWidget(this.data, {Key key}) : super(key: key) { | |||||
try { | |||||
model = SearchResultTabModel.fromJson(jsonDecode(data['data'])); | |||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | |||||
} | |||||
@override | |||||
_SearchResultTabWidgetState createState() => _SearchResultTabWidgetState(); | |||||
} | |||||
class _SearchResultTabWidgetState extends State<SearchResultTabWidget> { | |||||
TabController _tabController; | |||||
/// 联想点击事件 | |||||
_onThinkItemClick(SearchThinkModel model){ | |||||
} | |||||
@override | |||||
void initState() { | |||||
_tabController = TabController(length: widget?.model?.search_icon_list?.length ?? 0, vsync: ScrollableState()); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_tabController?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return _getMainWidget(widget?.model); | |||||
} | |||||
/// 获取主视图 | |||||
Widget _getMainWidget(SearchResultTabModel model) { | |||||
return Visibility( | |||||
replacement: SearchTabSkeleton(), | |||||
visible: !EmptyUtil.isEmpty(model), | |||||
child: _getTabar(model), | |||||
); | |||||
} | |||||
/// 获取TabBar | |||||
Widget _getTabar(SearchResultTabModel model) { | |||||
return Container( | |||||
margin: const EdgeInsets.only(/*left: 12.5, right: 12.5,*/ top: 5), | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
TabBar( | |||||
controller: _tabController, | |||||
isScrollable: true, | |||||
labelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), | |||||
unselectedLabelColor: HexColor.fromHex('#999999'), | |||||
labelColor: HexColor.fromHex('#FF4242'), | |||||
// indicatorSize: TabBarIndicatorSize.label, | |||||
indicator: MaterialIndicator( | |||||
height: 2.5, | |||||
topLeftRadius: 8, | |||||
topRightRadius: 8, | |||||
bottomLeftRadius: 8, | |||||
bottomRightRadius: 8, | |||||
color: HexColor.fromHex('#FF4242'), | |||||
horizontalPadding: 25, | |||||
), | |||||
tabs: model.search_icon_list.map((item) { | |||||
return MyTab( | |||||
icon: CachedNetworkImage( | |||||
imageUrl: item?.with_icon_color ?? '', | |||||
width: 14, | |||||
), | |||||
text: item.name, | |||||
); | |||||
}).toList(), | |||||
), | |||||
// SearchResultSortWidget(null), | |||||
Expanded( | |||||
child: _getStackWidget(model), | |||||
), | |||||
], | |||||
), | |||||
); | |||||
} | |||||
Widget _getStackWidget(SearchResultTabModel model){ | |||||
return Stack( | |||||
children: <Widget>[ | |||||
/// tabBraviwe | |||||
_getTabBarViewWidget(model), | |||||
Visibility( | |||||
visible: true, | |||||
child: Container(), | |||||
), | |||||
], | |||||
); | |||||
} | |||||
/// 联想列表 | |||||
Widget _getThinkListWidget(List<SearchThinkModel> model){ | |||||
return ListView.builder(itemBuilder: (context, index){ | |||||
SearchThinkModel item = model[index]; | |||||
return GestureDetector( | |||||
onTap: ()=> _onThinkItemClick(item), | |||||
child: Container( | |||||
decoration: BoxDecoration( | |||||
border: Border(bottom: BorderSide(width: 0.5, color: HexColor.fromHex('#EEEEEE'))) | |||||
), | |||||
padding: const EdgeInsets.only(top: 13, bottom: 13), | |||||
child: Text('${item?.keywords}', style: TextStyle( color: HexColor.fromHex('#333333'), fontSize: 14),), | |||||
), | |||||
); | |||||
}, | |||||
itemCount: model?.length ?? 0, | |||||
padding: const EdgeInsets.only(left: 12.5, right: 12.5), | |||||
shrinkWrap: true, | |||||
); | |||||
} | |||||
/// tabBraviwe | |||||
Widget _getTabBarViewWidget(SearchResultTabModel model){ | |||||
return TabBarView( | |||||
physics: NeverScrollableScrollPhysics(), | |||||
controller: _tabController, | |||||
children: model.search_icon_list.map((item) { | |||||
// TODO 这里需要和后台沟通改成页面的唯一标示 | |||||
return PageFactory.create('search_result_item', item.toJson()..['keywords']= widget?.model?.keywords ?? ''); | |||||
}).toList(), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
class WalletAppbarModel { | |||||
String appBarName; | |||||
String appBarNameColor; | |||||
String appBarBgColor; | |||||
String bgImg; | |||||
WalletAppbarModel( | |||||
{this.appBarName, this.appBarNameColor, this.appBarBgColor, this.bgImg}); | |||||
WalletAppbarModel.fromJson(Map<String, dynamic> json) { | |||||
appBarName = json['app_bar_name']; | |||||
appBarNameColor = json['app_bar_name_color']; | |||||
appBarBgColor = json['app_bar_bg_color']; | |||||
bgImg = json['bg_img']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['app_bar_name'] = this.appBarName; | |||||
data['app_bar_name_color'] = this.appBarNameColor; | |||||
data['app_bar_bg_color'] = this.appBarBgColor; | |||||
data['bg_img'] = this.bgImg; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,34 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_appbar/model/WalletAppbarModel.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class WalletAppbar extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
const WalletAppbar({Key key, this.data}) : super(key: key); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
var model = WalletAppbarModel.fromJson(json.decode(data['data'])); | |||||
return Container( | |||||
height: MediaQuery.of(context).padding.top + 56, | |||||
child: AppBar( | |||||
leading: Navigator.canPop(context) | |||||
? IconButton( | |||||
icon: Icon(Icons.arrow_back_ios), | |||||
onPressed: () { | |||||
Navigator.of(context).pop(); | |||||
}) | |||||
: Container(), | |||||
backgroundColor: HexColor.fromHex(model.appBarBgColor), | |||||
centerTitle: true, | |||||
title: Text( | |||||
model.appBarName, | |||||
style: TextStyle(color: HexColor.fromHex(model.appBarNameColor)), | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
class WalletBilModel { | |||||
String bilText; | |||||
String bilIcon; | |||||
String skipText; | |||||
String skipIdentifier; | |||||
WalletBilModel( | |||||
{this.bilText, this.bilIcon, this.skipText, this.skipIdentifier}); | |||||
WalletBilModel.fromJson(Map<String, dynamic> json) { | |||||
bilText = json['bil_text']; | |||||
bilIcon = json['bil_icon']; | |||||
skipText = json['skip_text']; | |||||
skipIdentifier = json['skip_identifier']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['bil_text'] = this.bilText; | |||||
data['bil_icon'] = this.bilIcon; | |||||
data['skip_text'] = this.skipText; | |||||
data['skip_identifier'] = this.skipIdentifier; | |||||
return data; | |||||
} | |||||
} |
@@ -0,0 +1,51 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_bil/model/wallet_bli_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_income/wallet_income_sk.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
///查看明细部件 | |||||
class WalletBil extends StatelessWidget { | |||||
Map<String, dynamic> data; | |||||
WalletBil(this.data, {Key key}) : super(key: key); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
WalletBilModel model; | |||||
if (data != null) { | |||||
model = WalletBilModel.fromJson(json.decode(data['data'])); | |||||
} | |||||
return data == null | |||||
? WalletIncomeSkeleton() | |||||
: Container( | |||||
decoration: BoxDecoration( | |||||
color: Colors.white, borderRadius: BorderRadius.circular(8)), | |||||
margin: EdgeInsets.only(left: 12.5, right: 12.5, top: 10), | |||||
child: ListTile( | |||||
title: Row( | |||||
mainAxisSize: MainAxisSize.min, | |||||
children: <Widget>[ | |||||
CachedNetworkImage( | |||||
imageUrl: model.bilIcon, | |||||
width: 36.w, | |||||
height: 36.w, | |||||
fit: BoxFit.fill, | |||||
), | |||||
SizedBox(width: 15.w,), | |||||
Text(model.bilText, style: TextStyle(fontSize: 24.sp),), | |||||
], | |||||
), | |||||
trailing: InkWell( | |||||
child: Text(model.skipText, style: TextStyle(color: Colors.grey),), | |||||
onTap: () { | |||||
///跳转??? | |||||
},), | |||||
)); | |||||
} | |||||
} |
@@ -0,0 +1,93 @@ | |||||
class WalletHeaderModel { | |||||
String headerImg; | |||||
String headerAvatar; | |||||
String headerCashOutText; | |||||
String headerCashOutTextColor; | |||||
String headerCashOutBtnImg; | |||||
List<HeaderBottomList> headerBottomList; | |||||
WalletHeaderModel( | |||||
{this.headerImg, | |||||
this.headerAvatar, | |||||
this.headerCashOutText, | |||||
this.headerCashOutTextColor, | |||||
this.headerCashOutBtnImg, | |||||
this.headerBottomList}); | |||||
WalletHeaderModel.fromJson(Map<String, dynamic> json) { | |||||
headerImg = json['header_img']; | |||||
headerAvatar = json['header_avatar']; | |||||
headerCashOutText = json['header_cash_out_text']; | |||||
headerCashOutTextColor = json['header_cash_out_text_color']; | |||||
headerCashOutBtnImg = json['header_cash_out_btn_img']; | |||||
if (json['header_bottom_list'] != null) { | |||||
headerBottomList = new List<HeaderBottomList>(); | |||||
json['header_bottom_list'].forEach((v) { | |||||
headerBottomList.add(new HeaderBottomList.fromJson(v)); | |||||
}); | |||||
} | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['header_img'] = this.headerImg; | |||||
data['header_avatar'] = this.headerAvatar; | |||||
data['header_cash_out_text'] = this.headerCashOutText; | |||||
data['header_cash_out_text_color'] = this.headerCashOutTextColor; | |||||
data['header_cash_out_btn_img'] = this.headerCashOutBtnImg; | |||||
if (this.headerBottomList != null) { | |||||
data['header_bottom_list'] = | |||||
this.headerBottomList.map((v) => v.toJson()).toList(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class HeaderBottomList { | |||||
String totalText; | |||||
String totalTextColor; | |||||
String totalValueColor; | |||||
String cashOutText; | |||||
String cashOutTextColor; | |||||
String cashOutValueColor; | |||||
String unfinalText; | |||||
String unfinalTextColor; | |||||
String unfinalValueColor; | |||||
HeaderBottomList( | |||||
{this.totalText, | |||||
this.totalTextColor, | |||||
this.totalValueColor, | |||||
this.cashOutText, | |||||
this.cashOutTextColor, | |||||
this.cashOutValueColor, | |||||
this.unfinalText, | |||||
this.unfinalTextColor, | |||||
this.unfinalValueColor}); | |||||
HeaderBottomList.fromJson(Map<String, dynamic> json) { | |||||
totalText = json['total_text']; | |||||
totalTextColor = json['total_text_color']; | |||||
totalValueColor = json['total_value_color']; | |||||
cashOutText = json['cash_out_text']; | |||||
cashOutTextColor = json['cash_out_text_color']; | |||||
cashOutValueColor = json['cash_out_value_color']; | |||||
unfinalText = json['unfinal_text']; | |||||
unfinalTextColor = json['unfinal_text_color']; | |||||
unfinalValueColor = json['unfinal_value_color']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['total_text'] = this.totalText; | |||||
data['total_text_color'] = this.totalTextColor; | |||||
data['total_value_color'] = this.totalValueColor; | |||||
data['cash_out_text'] = this.cashOutText; | |||||
data['cash_out_text_color'] = this.cashOutTextColor; | |||||
data['cash_out_value_color'] = this.cashOutValueColor; | |||||
data['unfinal_text'] = this.unfinalText; | |||||
data['unfinal_text_color'] = this.unfinalTextColor; | |||||
data['unfinal_value_color'] = this.unfinalValueColor; | |||||
return data; | |||||
} | |||||
} |
@@ -1,13 +1,123 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_data/model/wallet_header_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_data/wallet_data_sk.dart'; | import 'package:zhiying_base_widget/widgets/wallet/wallet_data/wallet_data_sk.dart'; | ||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class WalletData extends StatelessWidget { | class WalletData extends StatelessWidget { | ||||
final Map<String, dynamic> data; | |||||
const WalletData(this.data, {Key key}) : super(key: key); | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
print(data); | |||||
Map<String, dynamic> temp = json.decode(data['data']); | |||||
var model = WalletHeaderModel.fromJson(temp); | |||||
return Container( | return Container( | ||||
width: double.infinity, | width: double.infinity, | ||||
child: WalletDataSkeleton(), | |||||
child: data == null | |||||
? WalletDataSkeleton() | |||||
: Container( | |||||
margin: EdgeInsets.only(left: 12.5, right: 12.5,top: 10), | |||||
padding: EdgeInsets.only(left: 36.w, right: 26.w), | |||||
decoration: BoxDecoration( | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider(model.headerImg),fit: BoxFit.fill)), | |||||
height: 290.h, | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
children: <Widget>[ | |||||
Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
Row( | |||||
children: <Widget>[ | |||||
CachedNetworkImage( | |||||
imageUrl: model.headerAvatar, | |||||
height: 66.h, | |||||
width: 52.w, | |||||
), | |||||
Padding( | |||||
padding: const EdgeInsets.all(8.0), | |||||
child: Column( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
children: <Widget>[ | |||||
Text( | |||||
model.headerCashOutText, | |||||
style: TextStyle( | |||||
fontSize: 25.sp, | |||||
color: HexColor.fromHex( | |||||
model.headerCashOutTextColor)), | |||||
), | |||||
Text( | |||||
"没数据", | |||||
style: TextStyle( | |||||
fontSize: 25.sp, | |||||
color: HexColor.fromHex( | |||||
model.headerCashOutTextColor)), | |||||
), | |||||
], | |||||
), | |||||
) | |||||
], | |||||
), | |||||
GestureDetector( | |||||
child: Container( | |||||
decoration: BoxDecoration( | |||||
color: Colors.red, | |||||
borderRadius: BorderRadius.circular(10), | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider(""), | |||||
fit: BoxFit.fill)), | |||||
child: Padding( | |||||
padding: EdgeInsets.only( | |||||
left: 29.w, | |||||
right: 29.w, | |||||
top: 20.w, | |||||
bottom: 20.w), | |||||
child: Text( | |||||
"提现", | |||||
style: TextStyle(color: Colors.white), | |||||
), | |||||
), | |||||
), | |||||
) | |||||
], | |||||
), | |||||
Divider( | |||||
height: 1, | |||||
), | |||||
Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceAround, | |||||
children: _buildTopListItem(model?.headerBottomList)) | |||||
], | |||||
), | |||||
), | |||||
); | ); | ||||
} | } | ||||
///构建顶部Item | |||||
_buildTopListItem(List<HeaderBottomList> list) { | |||||
List<Widget> listWidget = List(); | |||||
for (var item in list) { | |||||
listWidget.add(Column( | |||||
mainAxisSize: MainAxisSize.min, | |||||
children: <Widget>[ | |||||
Text( | |||||
"9999", | |||||
style: TextStyle(color: Colors.red, fontSize: 30.sp), | |||||
), | |||||
Text( | |||||
"累计到账(元)", | |||||
style: TextStyle(color: Colors.grey, fontSize: 22.sp), | |||||
), | |||||
], | |||||
)); | |||||
} | |||||
return listWidget; | |||||
} | |||||
} | } |
@@ -6,7 +6,7 @@ class WalletDataCreater extends WidgetCreater { | |||||
@override | @override | ||||
List<Widget> createWidgets(Map<String, dynamic> model) { | List<Widget> createWidgets(Map<String, dynamic> model) { | ||||
return [ | return [ | ||||
WalletData(), | |||||
WalletData(model), | |||||
]; | ]; | ||||
} | } | ||||
} | } |
@@ -0,0 +1,226 @@ | |||||
class WalletDetailModel { | |||||
List<Providers> providers; | |||||
List<DateList> dateList; | |||||
ProviderDashbord providerDashbord; | |||||
WalletDetailModel({this.providers, this.dateList, this.providerDashbord}); | |||||
WalletDetailModel.fromJson(Map<String, dynamic> json) { | |||||
if (json['providers'] != null) { | |||||
providers = new List<Providers>(); | |||||
json['providers'].forEach((v) { | |||||
providers.add(new Providers.fromJson(v)); | |||||
}); | |||||
} | |||||
if (json['date_list'] != null) { | |||||
dateList = new List<DateList>(); | |||||
json['date_list'].forEach((v) { | |||||
dateList.add(new DateList.fromJson(v)); | |||||
}); | |||||
} | |||||
providerDashbord = json['provider_dashbord'] != null | |||||
? new ProviderDashbord.fromJson(json['provider_dashbord']) | |||||
: null; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
if (this.providers != null) { | |||||
data['providers'] = this.providers.map((v) => v.toJson()).toList(); | |||||
} | |||||
if (this.dateList != null) { | |||||
data['date_list'] = this.dateList.map((v) => v.toJson()).toList(); | |||||
} | |||||
if (this.providerDashbord != null) { | |||||
data['provider_dashbord'] = this.providerDashbord.toJson(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class Providers { | |||||
String type; | |||||
String name; | |||||
String unselectColor; | |||||
String selectColor; | |||||
String lineColor; | |||||
Providers( | |||||
{this.type, | |||||
this.name, | |||||
this.unselectColor, | |||||
this.selectColor, | |||||
this.lineColor}); | |||||
Providers.fromJson(Map<String, dynamic> json) { | |||||
type = json['type']; | |||||
name = json['name']; | |||||
unselectColor = json['unselect_color']; | |||||
selectColor = json['select_color']; | |||||
lineColor = json['line_color']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['type'] = this.type; | |||||
data['name'] = this.name; | |||||
data['unselect_color'] = this.unselectColor; | |||||
data['select_color'] = this.selectColor; | |||||
data['line_color'] = this.lineColor; | |||||
return data; | |||||
} | |||||
} | |||||
class DateList { | |||||
String text; | |||||
String textSelectColor; | |||||
String textUnselectColor; | |||||
String btnImg; | |||||
DateList( | |||||
{this.text, this.textSelectColor, this.textUnselectColor, this.btnImg}); | |||||
DateList.fromJson(Map<String, dynamic> json) { | |||||
text = json['text']; | |||||
textSelectColor = json['text_select_color']; | |||||
textUnselectColor = json['text_unselect_color']; | |||||
btnImg = json['btn_img']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['text'] = this.text; | |||||
data['text_select_color'] = this.textSelectColor; | |||||
data['text_unselect_color'] = this.textUnselectColor; | |||||
data['btn_img'] = this.btnImg; | |||||
return data; | |||||
} | |||||
} | |||||
class ProviderDashbord { | |||||
Finish finish; | |||||
SelfBuy selfBuy; | |||||
SelfBuy directPromote; | |||||
SelfBuy indirectPromote; | |||||
ProviderDashbord( | |||||
{this.finish, this.selfBuy, this.directPromote, this.indirectPromote}); | |||||
ProviderDashbord.fromJson(Map<String, dynamic> json) { | |||||
finish = | |||||
json['finish'] != null ? new Finish.fromJson(json['finish']) : null; | |||||
selfBuy = json['self_buy'] != null | |||||
? new SelfBuy.fromJson(json['self_buy']) | |||||
: null; | |||||
directPromote = json['direct_promote'] != null | |||||
? new SelfBuy.fromJson(json['direct_promote']) | |||||
: null; | |||||
indirectPromote = json['indirect_promote'] != null | |||||
? new SelfBuy.fromJson(json['indirect_promote']) | |||||
: null; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
if (this.finish != null) { | |||||
data['finish'] = this.finish.toJson(); | |||||
} | |||||
if (this.selfBuy != null) { | |||||
data['self_buy'] = this.selfBuy.toJson(); | |||||
} | |||||
if (this.directPromote != null) { | |||||
data['direct_promote'] = this.directPromote.toJson(); | |||||
} | |||||
if (this.indirectPromote != null) { | |||||
data['indirect_promote'] = this.indirectPromote.toJson(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class Finish { | |||||
String text; | |||||
String textColor; | |||||
String valueColor; | |||||
String bgImg; | |||||
Finish({this.text, this.textColor, this.valueColor, this.bgImg}); | |||||
Finish.fromJson(Map<String, dynamic> json) { | |||||
text = json['text']; | |||||
textColor = json['text_color']; | |||||
valueColor = json['value_color']; | |||||
bgImg = json['bg_img']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['text'] = this.text; | |||||
data['text_color'] = this.textColor; | |||||
data['value_color'] = this.valueColor; | |||||
data['bg_img'] = this.bgImg; | |||||
return data; | |||||
} | |||||
} | |||||
class SelfBuy { | |||||
String title; | |||||
String titleColor; | |||||
String leftBgImg; | |||||
String rightBgImg; | |||||
List<ItemList> itemList; | |||||
SelfBuy( | |||||
{this.title, | |||||
this.titleColor, | |||||
this.leftBgImg, | |||||
this.rightBgImg, | |||||
this.itemList}); | |||||
SelfBuy.fromJson(Map<String, dynamic> json) { | |||||
title = json['title']; | |||||
titleColor = json['title_color']; | |||||
leftBgImg = json['left_bg_img']; | |||||
rightBgImg = json['right_bg_img']; | |||||
if (json['list'] != null) { | |||||
itemList = new List<ItemList>(); | |||||
json['list'].forEach((v) { | |||||
itemList.add(new ItemList.fromJson(v)); | |||||
}); | |||||
} | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['title'] = this.title; | |||||
data['title_color'] = this.titleColor; | |||||
data['left_bg_img'] = this.leftBgImg; | |||||
data['right_bg_img'] = this.rightBgImg; | |||||
if (this.itemList != null) { | |||||
data['list'] = this.itemList.map((v) => v.toJson()).toList(); | |||||
} | |||||
return data; | |||||
} | |||||
} | |||||
class ItemList { | |||||
String text; | |||||
String textColor; | |||||
String valueColor; | |||||
ItemList({this.text, this.textColor, this.valueColor}); | |||||
ItemList.fromJson(Map<String, dynamic> json) { | |||||
text = json['text']; | |||||
textColor = json['text_color']; | |||||
valueColor = json['value_color']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['text'] = this.text; | |||||
data['text_color'] = this.textColor; | |||||
data['value_color'] = this.valueColor; | |||||
return data; | |||||
} | |||||
} |
@@ -1,18 +1,184 @@ | |||||
import 'dart:convert'; | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/withdraw_page/withdraw_page.dart'; | import 'package:zhiying_base_widget/pages/withdraw_page/withdraw_page.dart'; | ||||
import 'package:zhiying_base_widget/widgets/home/home_quick_entry/cached_network_image_util.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/model/wallet_detail_model.dart'; | |||||
import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/wallet_detail_sk.dart'; | import 'package:zhiying_base_widget/widgets/wallet/wallet_detail/wallet_detail_sk.dart'; | ||||
import 'package:flutter_screenutil/flutter_screenutil.dart'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class WalletDetail extends StatefulWidget { | |||||
final Map<String, dynamic> data; | |||||
const WalletDetail( | |||||
this.data, { | |||||
Key key, | |||||
}) : super(key: key); | |||||
@override | |||||
_WalletDetailState createState() => _WalletDetailState(); | |||||
} | |||||
class _WalletDetailState extends State<WalletDetail> | |||||
with TickerProviderStateMixin { | |||||
WalletDetailModel _model; | |||||
TabController _tabController; | |||||
@override | |||||
void initState() { | |||||
if (widget.data != null) { | |||||
_model = WalletDetailModel.fromJson(json.decode(widget.data['data'])); | |||||
_tabController = | |||||
TabController(length: _model.providers.length, vsync: this); | |||||
} | |||||
super.initState(); | |||||
} | |||||
class WalletDetail extends StatelessWidget { | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return GestureDetector( | |||||
child: WalletDetailSkeleton(), | |||||
onTap: () { | |||||
Navigator.push(context, MaterialPageRoute(builder: (context) { | |||||
return WithdrawPage(); | |||||
})); | |||||
}, | |||||
return Container( | |||||
margin: EdgeInsets.only(left: 12.5, right: 12.5), | |||||
child: Column( | |||||
children: <Widget>[ | |||||
Container( | |||||
child: TabBar( | |||||
// isScrollable: true, | |||||
controller: _tabController, | |||||
tabs: _buildTabs()), | |||||
), | |||||
Container( | |||||
height: 75.h, | |||||
child: ListView.builder( | |||||
padding: EdgeInsets.only(top: 16), | |||||
itemCount: _model.dateList.length, | |||||
scrollDirection: Axis.horizontal, | |||||
itemBuilder: _buildTimeItem), | |||||
), | |||||
Container( | |||||
height: 126.h, | |||||
margin: EdgeInsets.only(top: 16), | |||||
width: double.infinity, | |||||
decoration: BoxDecoration( | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider( | |||||
_model.providerDashbord.finish.bgImg), | |||||
fit: BoxFit.fill)), | |||||
child: Column( | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
Row( | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
Text( | |||||
"已结算", | |||||
style: TextStyle(color: Colors.black, fontSize: 22.sp), | |||||
), | |||||
InkWell( | |||||
child: Padding( | |||||
padding: const EdgeInsets.all(8.0), | |||||
child: CachedNetworkImage( | |||||
imageUrl: "", | |||||
width: 20.h, | |||||
height: 20.h, | |||||
fit: BoxFit.fill, | |||||
), | |||||
), | |||||
onTap: () { | |||||
///问好 | |||||
}) | |||||
], | |||||
), | |||||
Text( | |||||
"158", | |||||
style: TextStyle(color: Colors.red, fontSize: 40.sp), | |||||
) | |||||
], | |||||
), | |||||
), | |||||
Container( | |||||
child: ListView.builder( | |||||
itemCount: 3, | |||||
shrinkWrap: true, | |||||
physics: NeverScrollableScrollPhysics(), | |||||
itemBuilder: (context, index) { | |||||
return _buildBottomItem( | |||||
context, index, _model.providerDashbord); | |||||
}), | |||||
) | |||||
], | |||||
), | |||||
); | |||||
} | |||||
_buildTabs() { | |||||
List<Widget> listWidget = List(); | |||||
for (var item in _model.providers) { | |||||
listWidget.add(Tab( | |||||
child: Text( | |||||
item.name, | |||||
style: TextStyle(color: Colors.grey), | |||||
), | |||||
)); | |||||
} | |||||
return listWidget; | |||||
} | |||||
Widget _buildTimeItem(BuildContext context, int index) { | |||||
var item = _model.dateList[index]; | |||||
return Container( | |||||
margin: EdgeInsets.only(top: 0, left: 8, right: 8), | |||||
decoration: BoxDecoration( | |||||
color: Colors.grey[200], borderRadius: BorderRadius.circular(50)), | |||||
child: Padding( | |||||
padding: const EdgeInsets.only(left: 16, right: 16), | |||||
child: Center( | |||||
child: Text( | |||||
item.text, | |||||
style: TextStyle(color: Colors.grey), | |||||
)), | |||||
), | |||||
); | |||||
} | |||||
Widget _buildBottomItem( | |||||
BuildContext context, int index, ProviderDashbord dashbord) { | |||||
var item = dashbord.selfBuy; | |||||
return Container( | |||||
child: Column( | |||||
children: <Widget>[ | |||||
Text( | |||||
item.title, | |||||
style: TextStyle(color: HexColor.fromHex(item.titleColor)), | |||||
), | |||||
Row( | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | |||||
Expanded( | |||||
child: Container( | |||||
height: 123.h, | |||||
margin: EdgeInsets.only(right: 8), | |||||
decoration: BoxDecoration( | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider(item.leftBgImg), | |||||
fit: BoxFit.fill)), | |||||
child: Center(child: Text("ddd")), | |||||
), | |||||
), | |||||
Expanded( | |||||
child: Container( | |||||
height: 123.h, | |||||
margin: EdgeInsets.only(left: 8), | |||||
decoration: BoxDecoration( | |||||
image: DecorationImage( | |||||
image: CachedNetworkImageProvider(item.rightBgImg))), | |||||
child: Center(child: Text("dddd")), | |||||
)) | |||||
], | |||||
) | |||||
], | |||||
), | |||||
); | ); | ||||
} | } | ||||
} | } |
@@ -28,13 +28,18 @@ dependencies: | |||||
sharesdk_plugin: ^1.2.8 | sharesdk_plugin: ^1.2.8 | ||||
# 系统分享 | # 系统分享 | ||||
share_extend: ^1.1.9 | share_extend: ^1.1.9 | ||||
flutter_native_image: ^0.0.5 | |||||
#字符检测 | |||||
string_validator: 0.1.4 | |||||
intl: 0.15.7 | |||||
zhiying_comm: | |||||
path: ../zhiying_comm | |||||
dev_dependencies: | dev_dependencies: | ||||
flutter_test: | flutter_test: | ||||
sdk: flutter | sdk: flutter | ||||
zhiying_comm: | |||||
path: ../zhiying_comm | |||||
# For information on the generic Dart part of this file, see the | # For information on the generic Dart part of this file, see the | ||||
# following page: https://dart.dev/tools/pub/pubspec | # following page: https://dart.dev/tools/pub/pubspec | ||||