Sfoglia il codice sorgente

Merge branch 'master' of http://192.168.0.138:3000/FnuoOS_ZhiYing/zhiying_base_widget

# Conflicts:
#	pubspec.yaml
tags/0.0.1
Weller 4 anni fa
parent
commit
752e9f286b
88 ha cambiato i file con 5480 aggiunte e 679 eliminazioni
  1. +9
    -3
      .dart_tool/package_config.json
  2. +115
    -0
      lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_create.dart
  3. +246
    -0
      lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_goods_dialog.dart
  4. +183
    -0
      lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_no_goods_dialog.dart
  5. +50
    -0
      lib/dialog/global_dialog/intellect_search_goods_dialog/model/Intellect_search_set_model.dart
  6. +209
    -0
      lib/dialog/select_date_ym_dialog/select_date_ym_dialog.dart
  7. +135
    -0
      lib/pages/bil_detail_page/bil_detail_page.dart
  8. +53
    -0
      lib/pages/bil_detail_page/bil_detail_page_bloc.dart
  9. +5
    -0
      lib/pages/bil_detail_page/model/bil_detail_page_model.dart
  10. +2
    -1
      lib/pages/goods_details_page/goods_details_page.dart
  11. +46
    -0
      lib/pages/goods_details_page/goods_details_page_sk.dart
  12. +1
    -0
      lib/pages/home_page/home_page.dart
  13. +17
    -1
      lib/pages/main_page/main_page.dart
  14. +6
    -0
      lib/pages/search_page/bloc/search_bloc.dart
  15. +10
    -2
      lib/pages/search_page/bloc/search_repository.dart
  16. +47
    -0
      lib/pages/search_page/item/bloc/search_item_page_bloc.dart
  17. +15
    -0
      lib/pages/search_page/item/bloc/search_item_page_event.dart
  18. +26
    -0
      lib/pages/search_page/item/bloc/search_item_page_state.dart
  19. +34
    -0
      lib/pages/search_page/item/bloc/search_item_repostitory.dart
  20. +121
    -0
      lib/pages/search_page/item/search_item_page.dart
  21. +59
    -0
      lib/pages/search_page/notifier/search_tag_notifier.dart
  22. +78
    -35
      lib/pages/search_page/search_page.dart
  23. +0
    -183
      lib/pages/search_page/search_page2.dart
  24. +0
    -148
      lib/pages/search_page/search_page3.dart
  25. +46
    -0
      lib/pages/search_result_page/bloc/search_result_bloc.dart
  26. +18
    -0
      lib/pages/search_result_page/bloc/search_result_event.dart
  27. +60
    -0
      lib/pages/search_result_page/bloc/search_result_repository.dart
  28. +26
    -0
      lib/pages/search_result_page/bloc/search_result_state.dart
  29. +48
    -0
      lib/pages/search_result_page/item/bloc/search_result_item_bloc.dart
  30. +15
    -0
      lib/pages/search_result_page/item/bloc/search_result_item_event.dart
  31. +55
    -0
      lib/pages/search_result_page/item/bloc/search_result_item_repository.dart
  32. +23
    -0
      lib/pages/search_result_page/item/bloc/search_result_item_state.dart
  33. +16
    -0
      lib/pages/search_result_page/item/notifier/search_result_item_page_notifier.dart
  34. +195
    -0
      lib/pages/search_result_page/item/search_result_item_page.dart
  35. +109
    -0
      lib/pages/search_result_page/search_result_page.dart
  36. +61
    -0
      lib/pages/search_think_page/bloc/search_think_bloc.dart
  37. +31
    -0
      lib/pages/search_think_page/bloc/search_think_event.dart
  38. +35
    -0
      lib/pages/search_think_page/bloc/search_think_repository.dart
  39. +30
    -0
      lib/pages/search_think_page/bloc/search_think_state.dart
  40. +20
    -0
      lib/pages/search_think_page/model/search_think_model.dart
  41. +147
    -0
      lib/pages/search_think_page/search_think_page.dart
  42. +97
    -27
      lib/pages/wallet_page/wallet_page.dart
  43. +17
    -7
      lib/pages/wallet_page/wallet_page_bloc.dart
  44. +98
    -50
      lib/register.dart
  45. +18
    -0
      lib/utils/contants.dart
  46. +3
    -2
      lib/widgets/goods_details/detail_img/bloc/goods_details_img_repository.dart
  47. +11
    -0
      lib/widgets/goods_details/detail_img/model/goods_details_img_model.dart
  48. +7
    -1
      lib/widgets/goods_details/footer/goods_details_footer_widget.dart
  49. +6
    -1
      lib/widgets/home/home_goods/models/home_goods_model.dart
  50. +1
    -1
      lib/widgets/home/home_slide_banner/home_slide_banner.dart
  51. +0
    -1
      lib/widgets/home/home_sreach/home_sreach_creater.dart
  52. +11
    -4
      lib/widgets/home/home_sreach/home_sreach_widget.dart
  53. +2
    -1
      lib/widgets/mine/mine_header/mine_header_container.dart
  54. +0
    -129
      lib/widgets/search/history_tag/history_tag.dart
  55. +23
    -0
      lib/widgets/search/history_tag/model/search_history_model.dart
  56. +167
    -0
      lib/widgets/search/history_tag/search_history_tag.dart
  57. +55
    -0
      lib/widgets/search/hot_tag/model/search_hot_tag_model.dart
  58. +100
    -0
      lib/widgets/search/hot_tag/search_hot_tag_widget.dart
  59. +100
    -23
      lib/widgets/search/input/search_input_widget.dart
  60. +13
    -1
      lib/widgets/search/tabbar/model/search_tab_model.dart
  61. +2
    -2
      lib/widgets/search/tabbar/search_tab_creater.dart
  62. +119
    -36
      lib/widgets/search/tabbar/search_tab_widget.dart
  63. +1
    -1
      lib/widgets/search/widget/my_tab.dart
  64. +18
    -5
      lib/widgets/search/widget/text_tag_widget.dart
  65. +103
    -0
      lib/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart
  66. +26
    -0
      lib/widgets/search_result/goods_list/bloc/search_result_goods_list_event.dart
  67. +107
    -0
      lib/widgets/search_result/goods_list/bloc/search_result_goods_list_repository.dart
  68. +42
    -0
      lib/widgets/search_result/goods_list/bloc/search_result_goods_list_state.dart
  69. +2
    -2
      lib/widgets/search_result/goods_list/search_result_goods_list_sk.dart
  70. +192
    -0
      lib/widgets/search_result/goods_list/search_result_goods_list_widget.dart
  71. +39
    -0
      lib/widgets/search_result/search_input/model/search_result_input_model.dart
  72. +160
    -0
      lib/widgets/search_result/search_input/search_result_input.dart
  73. +126
    -0
      lib/widgets/search_result/sort/model/search_result_sort_model.dart
  74. +384
    -0
      lib/widgets/search_result/sort/search_result_sort_widget.dart
  75. +73
    -0
      lib/widgets/search_result/tarbar/model/search_result_tab_model.dart
  76. +23
    -0
      lib/widgets/search_result/tarbar/search_result_tab_creater.dart
  77. +22
    -0
      lib/widgets/search_result/tarbar/search_result_tab_sk.dart
  78. +163
    -0
      lib/widgets/search_result/tarbar/search_result_tab_widget.dart
  79. +25
    -0
      lib/widgets/wallet/wallet_appbar/model/WalletAppbarModel.dart
  80. +34
    -0
      lib/widgets/wallet/wallet_appbar/wallet_appbar.dart
  81. +25
    -0
      lib/widgets/wallet/wallet_bil/model/wallet_bli_model.dart
  82. +51
    -0
      lib/widgets/wallet/wallet_bil/wallet_bil.dart
  83. +93
    -0
      lib/widgets/wallet/wallet_data/model/wallet_header_model.dart
  84. +111
    -1
      lib/widgets/wallet/wallet_data/wallet_data.dart
  85. +1
    -1
      lib/widgets/wallet/wallet_data/wallet_data_creater.dart
  86. +226
    -0
      lib/widgets/wallet/wallet_detail/model/wallet_detail_model.dart
  87. +174
    -8
      lib/widgets/wallet/wallet_detail/wallet_detail.dart
  88. +7
    -2
      pubspec.yaml

+ 9
- 3
.dart_tool/package_config.json Vedi File

@@ -249,9 +249,9 @@
},
{
"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/",
"languageVersion": "2.5"
"languageVersion": "2.0"
},
{
"name": "jdsdk",
@@ -475,6 +475,12 @@
"packageUri": "lib/",
"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",
"rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/synchronized-2.2.0",
@@ -596,7 +602,7 @@
"languageVersion": "2.1"
}
],
"generated": "2020-09-29T08:01:12.048733Z",
"generated": "2020-09-29T09:19:18.536482Z",
"generator": "pub",
"generatorVersion": "2.7.2"
}

+ 115
- 0
lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_create.dart Vedi File

@@ -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);
}
}

+ 246
- 0
lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_goods_dialog.dart Vedi File

@@ -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),
),
)),
))
],
)
],
);
}
}

+ 183
- 0
lib/dialog/global_dialog/intellect_search_goods_dialog/intellect_search_no_goods_dialog.dart Vedi File

@@ -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),
)
],
),
);
}
}

+ 50
- 0
lib/dialog/global_dialog/intellect_search_goods_dialog/model/Intellect_search_set_model.dart Vedi File

@@ -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;
}
}

+ 209
- 0
lib/dialog/select_date_ym_dialog/select_date_ym_dialog.dart Vedi File

@@ -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;
}
}

+ 135
- 0
lib/pages/bil_detail_page/bil_detail_page.dart Vedi File

@@ -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());
}
}

+ 53
- 0
lib/pages/bil_detail_page/bil_detail_page_bloc.dart Vedi File

@@ -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);
}

+ 5
- 0
lib/pages/bil_detail_page/model/bil_detail_page_model.dart Vedi File

@@ -0,0 +1,5 @@


class BilDetailPageModel{

}

+ 2
- 1
lib/pages/goods_details_page/goods_details_page.dart Vedi File

@@ -6,6 +6,7 @@ import 'package:provider/provider.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_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/widgets/goods_details/footer/goods_details_footer_widget.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
@@ -120,7 +121,7 @@ class _GoodsDetailsContainerState extends State<GoodsDetailsContainer> {
if (state is GoodsDetailsPageLoadedState) {
return _getMainWidget(state?.model);
}
return _getMainWidget(null);
return GoodsDetailsPageSkeleton();
},
),
),


+ 46
- 0
lib/pages/goods_details_page/goods_details_page_sk.dart Vedi File

@@ -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(),
)
],
),
);
}
}

+ 1
- 0
lib/pages/home_page/home_page.dart Vedi File

@@ -36,6 +36,7 @@ class _HomePageState extends State<HomePage> {

@override
Widget build(BuildContext context) {
ScreenUtil.init(context, width: 750, height: 1334);
print('home_page build');
List<Map<String, dynamic>> tabs = _data;
if (tabs == null || tabs.length == 0) {


+ 17
- 1
lib/pages/main_page/main_page.dart Vedi File

@@ -2,9 +2,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.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/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/home/home_auth/home_auth.dart';
import 'package:zhiying_base_widget/widgets/others/mine_header_bg_widget.dart';
import 'package:zhiying_comm/util/base_bloc.dart';
@@ -47,7 +51,8 @@ class _MainPageContainer extends StatefulWidget {
_MainPageContainerState createState() => _MainPageContainerState();
}

class _MainPageContainerState extends State<_MainPageContainer> {
class _MainPageContainerState extends State<_MainPageContainer>
with WidgetsBindingObserver {
bool _isEnded = false;
ScrollController _controller = ScrollController();
MainPageBloc _bloc;
@@ -62,9 +67,17 @@ class _MainPageContainerState extends State<_MainPageContainer> {
// _refreshController.loadComplete();
}

@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
///智能粘贴板
// IntellectCreate.checkAndCreate(state, context);
super.didChangeAppLifecycleState(state);
}

@override
void dispose() {
_controller.dispose();
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@@ -88,6 +101,9 @@ class _MainPageContainerState extends State<_MainPageContainer> {
Provider.of<MainPageNotifier>(context, listen: false).reset();
}
});
///监听app生命周期变化
// WidgetsBinding.instance.addObserver(this);
IntellectCreate.checkAndCreateFirst(context);
super.initState();
}



+ 6
- 0
lib/pages/search_page/bloc/search_bloc.dart Vedi File

@@ -37,6 +37,12 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {

/// 初始化
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);
Logger.log('result = ${result.toString()}');


+ 10
- 2
lib/pages/search_page/bloc/search_repository.dart Vedi File

@@ -5,7 +5,7 @@ class SearchRepository {

/// 获取网络数据
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)) {
try {
_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 {


+ 47
- 0
lib/pages/search_page/item/bloc/search_item_page_bloc.dart Vedi File

@@ -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();
}
}
}

+ 15
- 0
lib/pages/search_page/item/bloc/search_item_page_event.dart Vedi File

@@ -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];
}

+ 26
- 0
lib/pages/search_page/item/bloc/search_item_page_state.dart Vedi File

@@ -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 {}

+ 34
- 0
lib/pages/search_page/item/bloc/search_item_repostitory.dart Vedi File

@@ -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;
}

}

+ 121
- 0
lib/pages/search_page/item/search_item_page.dart Vedi File

@@ -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;
}
}

+ 59
- 0
lib/pages/search_page/notifier/search_tag_notifier.dart Vedi File

@@ -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();
}
}

+ 78
- 35
lib/pages/search_page/search_page.dart Vedi File

@@ -1,6 +1,10 @@
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:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';

import 'bloc/search_bloc.dart';
import 'bloc/search_repository.dart';
@@ -15,9 +19,30 @@ class SearchPage extends StatelessWidget {

@override
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> {
/// tab轮播
TabController _tabController;
ScrollController _controller = ScrollController();

@override
void initState() {
_tabController = TabController(length:0, vsync: ScrollableState());
_tabController = TabController(length: 6, vsync: ScrollableState());
super.initState();
}

@override
void dispose() {
_controller?.dispose();
_tabController?.dispose();
super.dispose();
}
@@ -94,44 +117,64 @@ class _SearchPageContianerState extends State<SearchPageContianer> {
Widget _getMainWidget(List<Map<String, dynamic>> datas) {
return Scaffold(
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;

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;
}

// 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;
// }
}

+ 0
- 183
lib/pages/search_page/search_page2.dart Vedi File

@@ -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;
}

+ 0
- 148
lib/pages/search_page/search_page3.dart Vedi File

@@ -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;
}
}


+ 46
- 0
lib/pages/search_result_page/bloc/search_result_bloc.dart Vedi File

@@ -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();
}

}
}

+ 18
- 0
lib/pages/search_result_page/bloc/search_result_event.dart Vedi File

@@ -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];
}

+ 60
- 0
lib/pages/search_result_page/bloc/search_result_repository.dart Vedi File

@@ -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('');
}
}

+ 26
- 0
lib/pages/search_result_page/bloc/search_result_state.dart Vedi File

@@ -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 {}

+ 48
- 0
lib/pages/search_result_page/item/bloc/search_result_item_bloc.dart Vedi File

@@ -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();
}
}
}

+ 15
- 0
lib/pages/search_result_page/item/bloc/search_result_item_event.dart Vedi File

@@ -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];
}

+ 55
- 0
lib/pages/search_result_page/item/bloc/search_result_item_repository.dart Vedi File

@@ -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;
}
}

+ 23
- 0
lib/pages/search_result_page/item/bloc/search_result_item_state.dart Vedi File

@@ -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 {}

+ 16
- 0
lib/pages/search_result_page/item/notifier/search_result_item_page_notifier.dart Vedi File

@@ -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();
}
}

+ 195
- 0
lib/pages/search_result_page/item/search_result_item_page.dart Vedi File

@@ -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;
}
}

+ 109
- 0
lib/pages/search_result_page/search_result_page.dart Vedi File

@@ -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;
}
}

+ 61
- 0
lib/pages/search_think_page/bloc/search_think_bloc.dart Vedi File

@@ -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);
}
}

+ 31
- 0
lib/pages/search_think_page/bloc/search_think_event.dart Vedi File

@@ -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 => [];
}

+ 35
- 0
lib/pages/search_think_page/bloc/search_think_repository.dart Vedi File

@@ -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');
}
}

+ 30
- 0
lib/pages/search_think_page/bloc/search_think_state.dart Vedi File

@@ -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 => [];
}

+ 20
- 0
lib/pages/search_think_page/model/search_think_model.dart Vedi File

@@ -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;
}
}

+ 147
- 0
lib/pages/search_think_page/search_think_page.dart Vedi File

@@ -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,
),
),
);
}
}

+ 97
- 27
lib/pages/wallet_page/wallet_page.dart Vedi File

@@ -4,10 +4,20 @@ import 'package:provider/provider.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_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';

import 'wallet_page_bloc.dart';
import 'wallet_page_bloc.dart';

class WalletPage extends StatefulWidget {
final Map<String, dynamic> data;

const WalletPage({Key key, this.data}) : super(key: key);

@override
_WalletPageState createState() => _WalletPageState();
}
@@ -22,14 +32,19 @@ class _WalletPageState extends State<WalletPage> {
ChangeNotifierProvider.value(value: MainPageNotifier()),
ChangeNotifierProvider.value(value: MainPageBgNotifier()),
],
child: _WalletPageContainer(),
child: BlocProvider<WalletPageBloc>(
bloc: WalletPageBloc(),
child: _WalletPageContainer(data: widget.data),
),
),
);
}
}

class _WalletPageContainer extends StatefulWidget {
_WalletPageContainer({Key key}) : super(key: key);
_WalletPageContainer({Key key, this.data}) : super(key: key);

final Map<String, dynamic> data;

@override
_WalletPageContainerState createState() => _WalletPageContainerState();
@@ -40,8 +55,14 @@ class _WalletPageContainerState extends State<_WalletPageContainer> {
final RefreshController _refreshController =
RefreshController(initialRefresh: false);

WalletPageBloc _pageBloc;

@override
void initState() {
_pageBloc = BlocProvider.of<WalletPageBloc>(context);
if (widget.data.containsKey(Constants.SkipIdentifierName)) {
_pageBloc.loadData(widget.data[Constants.SkipIdentifierName]);
}
super.initState();
}

@@ -53,6 +74,7 @@ class _WalletPageContainerState extends State<_WalletPageContainer> {

@override
Widget build(BuildContext context) {
ScreenUtil.init(context, width: 750, height: 1334);
return SmartRefresher(
controller: _refreshController,
enablePullDown: false,
@@ -67,39 +89,87 @@ class _WalletPageContainerState extends State<_WalletPageContainer> {
MineHeaderBgWidget(
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();
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;
}
}

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
- 7
lib/pages/wallet_page/wallet_page_bloc.dart Vedi File

@@ -17,13 +17,23 @@ class WalletPageBloc extends BlocBase {
_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);
}
}

+ 98
- 50
lib/register.dart Vedi File

@@ -1,17 +1,22 @@
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:flutter/cupertino.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/launch_page/launch_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/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_mobile/security_mobile.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/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/webview/base_webview.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_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/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/input/search_input_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_detail/wallet_detail.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/title/goods_details_title_widget.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 {
/// 初始化方法
@@ -79,10 +100,14 @@ class BaseWidgetRegister {
PageFactory.regist('homePage', (model) => LaunchPage());
PageFactory.regist('pub.flutter.index', (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('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_quick', (model) => LoginQuickPage(model));
// PageFactory.regist('login_account', (model) => LoginAccountPage(model));
@@ -130,12 +155,10 @@ class BaseWidgetRegister {
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
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', 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
WidgetFactory.regist('search_index_icon_list', SearcchTabCreater());
// 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提示
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_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(
'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(
// 'wallet_detail', DefaultWidgetCreater((model) => WalletDetail()));
// 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(
'wallet_income', DefaultWidgetCreater((model) => WalletIncome()));

//======================= 账单明细
}
}

+ 18
- 0
lib/utils/contants.dart Vedi File

@@ -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

}

+ 3
- 2
lib/widgets/goods_details/detail_img/bloc/goods_details_img_repository.dart Vedi File

@@ -24,8 +24,9 @@ class GoodsDetailsImgRepository {
try {
if(!EmptyUtil.isEmpty(_model)) {
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){



+ 11
- 0
lib/widgets/goods_details/detail_img/model/goods_details_img_model.dart Vedi File

@@ -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() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['title'] = this.title;


+ 7
- 1
lib/widgets/goods_details/footer/goods_details_footer_widget.dart Vedi File

@@ -40,7 +40,13 @@ class GooddsDetailsFooterContainer extends StatefulWidget {
class _GooddsDetailsFooterContainerState
extends State<GooddsDetailsFooterContainer> {
/// 打开首页
void _openHome() {}
void _openHome() {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (BuildContext context) => PageFactory.create('homePage', null)),
(Route<dynamic> route) => false,
);
}

/// 收藏
void _collectOnClick() {}


+ 6
- 1
lib/widgets/home/home_goods/models/home_goods_model.dart Vedi File

@@ -1,4 +1,6 @@
class HomeGoodsModel {
import 'package:equatable/equatable.dart';

class HomeGoodsModel extends Equatable {
String provider;
String providerName;
String goodId;
@@ -53,5 +55,8 @@ class HomeGoodsModel {
data['inorder_count'] = this.inorderCount;
return data;
}

@override
List<Object> get props => [this.goodId, this.provider, this.providerName];
}


+ 1
- 1
lib/widgets/home/home_slide_banner/home_slide_banner.dart Vedi File

@@ -100,7 +100,7 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> {
onTap: (index) => _itemOnClick(datas.index_carousel_list[index]),
pagination: _getSwiperStyleByType(datas, datas?.index_carousel_list?.length ?? 0),
onIndexChanged: (index) {
print('切换下一页');
//print('切换下一页');
Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container(
width: double.infinity,
height: 200,


+ 0
- 1
lib/widgets/home/home_sreach/home_sreach_creater.dart Vedi File

@@ -1,6 +1,5 @@
import 'package:flutter/material.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';

class HomeSreachCreater extends WidgetCreater {


+ 11
- 4
lib/widgets/home/home_sreach/home_sreach_widget.dart Vedi File

@@ -3,6 +3,7 @@ import 'dart:ui';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:zhiying_base_widget/pages/search_page/search_page.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

class HomeSreachDeleagater extends SliverPersistentHeaderDelegate {
@@ -67,6 +68,15 @@ class _HomeSreachContainer extends StatelessWidget {

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
Widget build(BuildContext context) {
List<Widget> widgets = List();
@@ -94,10 +104,7 @@ class _HomeSreachContainer extends StatelessWidget {
widgets.add(Expanded(
child: GestureDetector(
child: _getSreachWidget(),
onTap: () {
SkipModel skipModel = SkipModel.fromJson(model);
RouterUtil.route(skipModel, null, context);
},
onTap: () => _openSreach(context),
),
));



+ 2
- 1
lib/widgets/mine/mine_header/mine_header_container.dart Vedi File

@@ -64,7 +64,8 @@ class _MineHeaderContainerState extends State<MineHeaderContainer> {
),
),
onTap: () async {
await RouterUtil.route(SkipModel.fromJson(widget.json), widget.json, context);
await RouterUtil.route(SkipModel.fromJson(widget.json),
widget.json, context);
_bloc.loadData();
},
),


+ 0
- 129
lib/widgets/search/history_tag/history_tag.dart Vedi File

@@ -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();
}
}

+ 23
- 0
lib/widgets/search/history_tag/model/search_history_model.dart Vedi File

@@ -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;
}
}

+ 167
- 0
lib/widgets/search/history_tag/search_history_tag.dart Vedi File

@@ -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();
}
}

+ 55
- 0
lib/widgets/search/hot_tag/model/search_hot_tag_model.dart Vedi File

@@ -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;
}
}

+ 100
- 0
lib/widgets/search/hot_tag/search_hot_tag_widget.dart Vedi File

@@ -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',
);
}
}

+ 100
- 23
lib/widgets/search/input/search_input_widget.dart Vedi File

@@ -1,11 +1,18 @@
import 'dart:convert';
import 'dart:ui';
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/search/input/model/search_input_model.dart';
import 'package:zhiying_base_widget/widgets/search/input/search_input_sk.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:provider/provider.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> {
/// 点击搜索按钮
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;
TextEditingController _editingController;
@@ -65,32 +100,63 @@ class _SearchInputWidgetState extends State<SearchInputWidget> {
/// 获取主视图
Widget _getMainWidget(SearchInputModel model) {
return Container(
color: Colors.white,
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(
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
Widget _getSearchIconWidget(SearchInputModel model) {
return Container(
@@ -109,10 +175,18 @@ class _SearchInputWidgetState extends State<SearchInputWidget> {
return Container(
height: double.infinity,
alignment: Alignment.centerLeft,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: HexColor.fromHex('#F9F9F9')),
// padding: const EdgeInsets.symmetric(vertical: 6),
child: TextField(
showCursor: true,
// readOnly: true,
// onTap: ()=> _openSearchThinkPage(),
onChanged: (val)=> _searchInputChange(val),
cursorWidth: 1,
onSubmitted: (text) => _onSearchButtomClick(),
controller: _editingController,
focusNode: _focusNode,
cursorColor: Colors.transparent,
style: TextStyle(fontSize: 14, color: HexColor.fromHex('#333333')),
decoration: InputDecoration(
filled: false,
@@ -124,7 +198,7 @@ class _SearchInputWidgetState extends State<SearchInputWidget> {
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
enabledBorder: InputBorder.none,
hintText: '搜索更多优惠商品',
hintText: model?.search_inpu_hint_text ?? '搜索更多优惠商品',
hintStyle: TextStyle(color: HexColor.fromHex('#999999'), fontSize: 14),
),
),
@@ -139,11 +213,14 @@ class _SearchInputWidgetState extends State<SearchInputWidget> {
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 17.5, vertical: 6),
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),
),
child: Text(
'搜索',
model?.search_button ?? '搜索',
style: TextStyle(color: HexColor.fromHex('#FFFFFF'), fontSize: 14),
),
),


+ 13
- 1
lib/widgets/search/tabbar/model/search_tab_model.dart Vedi File

@@ -26,8 +26,18 @@ class SearchTabItemModel {
String name_select_color;
String type;
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) {
return SearchTabItemModel(
@@ -38,6 +48,7 @@ class SearchTabItemModel {
name_select_color: json['name_select_color'],
type: json['type'],
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['type'] = this.type;
data['with_icon_color'] = this.with_icon_color;
data['skip_identifier'] = this.skip_identifier;
return data;
}
}

+ 2
- 2
lib/widgets/search/tabbar/search_tab_creater.dart Vedi File

@@ -13,12 +13,12 @@ class SearcchTabCreater extends WidgetCreater{
// SearchTabWidget(model),
// ),
// ),
SearchTabWidget(model),
Expanded(child: SearchTabWidget(model)),
];
}

@override
bool isSliverChild() {
return true;
return false;
}
}

+ 119
- 36
lib/widgets/search/tabbar/search_tab_widget.dart Vedi File

@@ -3,14 +3,18 @@ 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_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/search/tabbar/search_tab_sk.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:flutter_bloc/flutter_bloc.dart';
import 'model/search_tab_model.dart';


class SearchTabWidget extends StatefulWidget {
final Map<String, dynamic> data;
SearchTabModel model;
@@ -29,12 +33,25 @@ class SearchTabWidget extends StatefulWidget {

class _SearchTabWidgetState extends State<SearchTabWidget> {
TabController _tabController;
int _currentIndex = 0;

/// 联想列表的item点击事件
_onThinkItemClick(SearchThinkModel model){
Navigator.push(context, MaterialPageRoute(
builder: (_)=> SearchResultPage(model.toJson())
));
}

@override
void initState() {

_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();
}
@@ -62,44 +79,110 @@ class _SearchTabWidgetState extends State<SearchTabWidget> {
/// 获取TabBar
Widget _getTabar(SearchTabModel model) {
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,
),
);
}
}

}

+ 1
- 1
lib/widgets/search/widget/my_tab.dart Vedi File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

const double _kTabHeight = 46.0;
const double _kTextAndIconTabHeight = 40.0;
const double _kTextAndIconTabHeight = 35.0;

/// A material design [TabBar] tab.
///


+ 18
- 5
lib/widgets/search/widget/text_tag_widget.dart Vedi File

@@ -1,6 +1,7 @@
import 'package:flutter/cupertino.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';

/**
@@ -16,14 +17,13 @@ class TextTagWidget extends StatefulWidget {
String text;
EdgeInsets margin;
EdgeInsets padding;

TextStyle textStyle;

Color backgroundColor;
Color borderColor;

double borderRadius;

String icon;

TextTagWidget(
this.text, {
this.margin = const EdgeInsets.all(4),
@@ -31,6 +31,7 @@ class TextTagWidget extends StatefulWidget {
this.textStyle,
this.backgroundColor,
this.borderColor,
this.icon,
this.borderRadius = 20.0,
}) {
if (this.borderColor == null) {
@@ -62,10 +63,22 @@ class TextTagWidget extends StatefulWidget {
class _TestPageState extends State<TextTagWidget> {
@override
Widget build(BuildContext context) {

if(EmptyUtil.isEmpty(widget.icon)) {
return buildTag();
}else{
return buildTag();
}
}

/// 构建按钮
Widget buildTag(){
return Container(

margin: widget.margin,
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(),
);
}


+ 103
- 0
lib/widgets/search_result/goods_list/bloc/search_result_goods_list_bloc.dart Vedi File

@@ -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();
}
}
}

+ 26
- 0
lib/widgets/search_result/goods_list/bloc/search_result_goods_list_event.dart Vedi File

@@ -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);
}

+ 107
- 0
lib/widgets/search_result/goods_list/bloc/search_result_goods_list_repository.dart Vedi File

@@ -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;
}
}

+ 42
- 0
lib/widgets/search_result/goods_list/bloc/search_result_goods_list_state.dart Vedi File

@@ -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];
}

lib/pages/sreach_result_page/sreach_result_page.dart → lib/widgets/search_result/goods_list/search_result_goods_list_sk.dart Vedi File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';

///
/// 搜索结果页面
/// 商品列表的骨架图
///
class SreachResultPage extends StatelessWidget {
class SearchResultGoodsListSkeleton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container();

+ 192
- 0
lib/widgets/search_result/goods_list/search_result_goods_list_widget.dart Vedi File

@@ -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'),
// );
// }
}

+ 39
- 0
lib/widgets/search_result/search_input/model/search_result_input_model.dart Vedi File

@@ -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;
}
}

+ 160
- 0
lib/widgets/search_result/search_input/search_result_input.dart Vedi File

@@ -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),
),
),
),
);
}

}

+ 126
- 0
lib/widgets/search_result/sort/model/search_result_sort_model.dart Vedi File

@@ -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;
}
}

+ 384
- 0
lib/widgets/search_result/sort/search_result_sort_widget.dart Vedi File

@@ -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,
),
),
);
}
}

+ 73
- 0
lib/widgets/search_result/tarbar/model/search_result_tab_model.dart Vedi File

@@ -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;
}
}

+ 23
- 0
lib/widgets/search_result/tarbar/search_result_tab_creater.dart Vedi File

@@ -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)
),
];
}


}

+ 22
- 0
lib/widgets/search_result/tarbar/search_result_tab_sk.dart Vedi File

@@ -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),
],
),
);
}
}

+ 163
- 0
lib/widgets/search_result/tarbar/search_result_tab_widget.dart Vedi File

@@ -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(),
);
}

}

+ 25
- 0
lib/widgets/wallet/wallet_appbar/model/WalletAppbarModel.dart Vedi File

@@ -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;
}
}

+ 34
- 0
lib/widgets/wallet/wallet_appbar/wallet_appbar.dart Vedi File

@@ -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)),
),
),
);
}
}

+ 25
- 0
lib/widgets/wallet/wallet_bil/model/wallet_bli_model.dart Vedi File

@@ -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;
}
}

+ 51
- 0
lib/widgets/wallet/wallet_bil/wallet_bil.dart Vedi File

@@ -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: () {
///跳转???
},),
));
}
}

+ 93
- 0
lib/widgets/wallet/wallet_data/model/wallet_header_model.dart Vedi File

@@ -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;
}
}

+ 111
- 1
lib/widgets/wallet/wallet_data/wallet_data.dart Vedi File

@@ -1,13 +1,123 @@
import 'dart:convert';
import 'package:flutter/cupertino.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:cached_network_image/cached_network_image.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

class WalletData extends StatelessWidget {
final Map<String, dynamic> data;

const WalletData(this.data, {Key key}) : super(key: key);

@override
Widget build(BuildContext context) {

print(data);
Map<String, dynamic> temp = json.decode(data['data']);
var model = WalletHeaderModel.fromJson(temp);
return Container(
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;
}
}

+ 1
- 1
lib/widgets/wallet/wallet_data/wallet_data_creater.dart Vedi File

@@ -6,7 +6,7 @@ class WalletDataCreater extends WidgetCreater {
@override
List<Widget> createWidgets(Map<String, dynamic> model) {
return [
WalletData(),
WalletData(model),
];
}
}

+ 226
- 0
lib/widgets/wallet/wallet_detail/model/wallet_detail_model.dart Vedi File

@@ -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;
}
}

+ 174
- 8
lib/widgets/wallet/wallet_detail/wallet_detail.dart Vedi File

@@ -1,18 +1,184 @@
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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: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
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")),
))
],
)
],
),
);
}
}

+ 7
- 2
pubspec.yaml Vedi File

@@ -28,13 +28,18 @@ dependencies:
sharesdk_plugin: ^1.2.8
# 系统分享
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:
flutter_test:
sdk: flutter

zhiying_comm:
path: ../zhiying_comm

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec


Caricamento…
Annulla
Salva