Browse Source

1、DIY页面的实现

2、商品详情的Notifier修改
3、首页去掉 暂无数据 提示
4、微信导师的协议修改
5、商品列表的骨架图添加
tags/0.0.2+11
PH2 4 years ago
parent
commit
9fec7dcfd4
42 changed files with 2298 additions and 400 deletions
  1. +67
    -0
      lib/pages/custom_page/bloc/custom_item_page_bloc.dart
  2. +13
    -0
      lib/pages/custom_page/bloc/custom_item_page_event.dart
  3. +56
    -0
      lib/pages/custom_page/bloc/custom_item_page_repository.dart
  4. +32
    -0
      lib/pages/custom_page/bloc/custom_item_page_state.dart
  5. +22
    -6
      lib/pages/custom_page/bloc/custom_page_repository.dart
  6. +7
    -1
      lib/pages/custom_page/bloc/custom_page_state.dart
  7. +188
    -0
      lib/pages/custom_page/custom_item_page.dart
  8. +213
    -254
      lib/pages/custom_page/custom_page.dart
  9. +4
    -3
      lib/pages/goods_details_page/goods_details_page.dart
  10. +14
    -14
      lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart
  11. +3
    -3
      lib/pages/main_page/main_page.dart
  12. +2
    -4
      lib/pages/main_page/main_page_skeleton.dart
  13. +4
    -4
      lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart
  14. +18
    -6
      lib/register.dart
  15. +0
    -16
      lib/widgets/custom/appbar/custom_appbar_creater.dart
  16. +0
    -45
      lib/widgets/custom/appbar/custom_appbar_widget.dart
  17. +4
    -0
      lib/widgets/custom/multi_nav/bloc/bloc.dart
  18. +50
    -0
      lib/widgets/custom/multi_nav/bloc/custom_quick_entry_bloc.dart
  19. +18
    -0
      lib/widgets/custom/multi_nav/bloc/custom_quick_entry_event.dart
  20. +75
    -0
      lib/widgets/custom/multi_nav/bloc/custom_quick_entry_repository.dart
  21. +40
    -0
      lib/widgets/custom/multi_nav/bloc/custom_quick_entry_state.dart
  22. +18
    -0
      lib/widgets/custom/multi_nav/cached_network_image_util.dart
  23. +373
    -0
      lib/widgets/custom/multi_nav/custom_quick_entry.dart
  24. +20
    -0
      lib/widgets/custom/multi_nav/custom_quick_entry_creater.dart
  25. +53
    -0
      lib/widgets/custom/multi_nav/custom_quick_entry_sk.dart
  26. +187
    -0
      lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart
  27. +58
    -1
      lib/widgets/custom/search/custom_search_widget.dart
  28. +157
    -0
      lib/widgets/custom/search/model/custom_search_model.dart
  29. +5
    -0
      lib/widgets/custom/slide_banner/bloc/bloc.dart
  30. +43
    -0
      lib/widgets/custom/slide_banner/bloc/custom_slide_banner_bloc.dart
  31. +14
    -0
      lib/widgets/custom/slide_banner/bloc/custom_slide_banner_event.dart
  32. +45
    -0
      lib/widgets/custom/slide_banner/bloc/custom_slide_banner_repository.dart
  33. +44
    -0
      lib/widgets/custom/slide_banner/bloc/custom_slide_banner_state.dart
  34. +224
    -0
      lib/widgets/custom/slide_banner/custom_slide_banner.dart
  35. +22
    -0
      lib/widgets/custom/slide_banner/custom_slide_banner_creater.dart
  36. +21
    -0
      lib/widgets/custom/slide_banner/custom_slide_banner_sk.dart
  37. +126
    -0
      lib/widgets/custom/slide_banner/model/custom_slide_banner_model.dart
  38. +10
    -8
      lib/widgets/goods_details/recommend/goods_detail_commend_list.dart
  39. +35
    -31
      lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart
  40. +1
    -1
      lib/widgets/home/home_goods/home_goods.dart
  41. +9
    -3
      lib/widgets/home/home_slide_banner/home_slide_banner.dart
  42. +3
    -0
      lib/widgets/mine/mine_header/mine_header_container.dart

+ 67
- 0
lib/pages/custom_page/bloc/custom_item_page_bloc.dart View File

@@ -0,0 +1,67 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:zhiying_base_widget/pages/custom_page/bloc/custom_item_page_repository.dart';
import 'custom_item_page_state.dart';
import 'custom_item_page_event.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomItemPageBloc extends Bloc<CustomItemPageEvent, CustomItemPageState> {
// CustomItemPageBloc() : super(CustomItemPageInitial());

CustomItemPageRepository repository;

CustomItemPageBloc(this.repository);

@override
CustomItemPageState get initialState => CustomItemPageInitial();

@override
Stream<CustomItemPageState> mapEventToState(
CustomItemPageEvent event,
) async* {
/// 初始化
if (event is CustomItemPageInitEvent) {
yield* _mapInitEventToState(event);
}

/// 下拉刷新
if (event is CustomItemPageRefreshEvent) {
yield* _mapRefreshEventToState(event);
}

/// 上拉更多
if (event is CustomItemPageLoadEvent) {
yield* _mapLoadEventToState(event);
}
}

/// 初始化
Stream<CustomItemPageState> _mapInitEventToState(CustomItemPageInitEvent event) async* {
var cacheStyle = await repository.fetchCacheStyle();
if (!EmptyUtil.isEmpty(cacheStyle)) {
yield CustomItemPageLoadedState(model: cacheStyle);
}
var netStyle = await repository.fetchNetStyle();
if (!EmptyUtil.isEmpty(netStyle) && netStyle is List) {
yield CustomItemPageLoadedState(model: netStyle);
} else {
yield CustomItemPageInitErrorState();
}
}

/// 下拉刷新
Stream<CustomItemPageState> _mapRefreshEventToState(CustomItemPageRefreshEvent event) async* {
var netStyle = await repository.fetchNetStyle();
if (!EmptyUtil.isEmpty(netStyle)) {
yield CustomItemPageRefreshSuccessState();
yield CustomItemPageLoadedState(model: netStyle);
} else {
yield CustomItemPageRefreshErrorState();
yield CustomItemPageErrorState();
}
}

/// 上拉更多
Stream<CustomItemPageState> _mapLoadEventToState(CustomItemPageLoadEvent event) async* {}
}

+ 13
- 0
lib/pages/custom_page/bloc/custom_item_page_event.dart View File

@@ -0,0 +1,13 @@
import 'package:meta/meta.dart';

@immutable
abstract class CustomItemPageEvent {}

/// 初始化
class CustomItemPageInitEvent extends CustomItemPageEvent {}

/// 下拉刷新
class CustomItemPageRefreshEvent extends CustomItemPageEvent {}

/// 上拉更多
class CustomItemPageLoadEvent extends CustomItemPageEvent {}

+ 56
- 0
lib/pages/custom_page/bloc/custom_item_page_repository.dart View File

@@ -0,0 +1,56 @@
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomItemPageRepository {
final Map<String, dynamic> data;
final int tabIndex;
final String modId;
final String modPid;

CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid);

/// 获取网络Style
Future<List<Map<String, dynamic>>> fetchNetStyle() async {
try {
String reqUrl = _buildRequestUrl();
if (!EmptyUtil.isEmpty(reqUrl)) {
var result = await NetUtil.post(reqUrl, method: NetMethod.GET, cache: true);
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
List mobList = !EmptyUtil.isEmpty(data) ? List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA][tabIndex.toString()]) : List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
if (!EmptyUtil.isEmpty(mobList)) {
return mobList.map((e) => Map<String, dynamic>.from(e)).toList();
}
}
}
} catch (e, s) {
Logger.error(e, s);
}
return null;
}

/// 获取缓存Style
Future<List<Map<String, dynamic>>> fetchCacheStyle() async {
try {
String reqUrl = _buildRequestUrl();
if (!EmptyUtil.isEmpty(reqUrl)) {
var result = await NetUtil.getRequestCachedData(reqUrl);
if (!EmptyUtil.isEmpty(result)) {
List mobList = !EmptyUtil.isEmpty(data) ? List.from(result[tabIndex.toString()]) : List.from(result);
if (!EmptyUtil.isEmpty(mobList)) {
return mobList.map((e) => Map<String, dynamic>.from(e)).toList();
}
}
}
} catch (e, s) {
Logger.error(e, s);
}
return null;
}

String _buildRequestUrl() {
if (!EmptyUtil.isEmpty(data)) {
return '/api/v1/custom/mod/$modId';
} else {
return '/api/v1/custom/mod/${modPid}?is_cate=1';
}
}
}

+ 32
- 0
lib/pages/custom_page/bloc/custom_item_page_state.dart View File

@@ -0,0 +1,32 @@
import 'package:meta/meta.dart';

@immutable
abstract class CustomItemPageState {}

/// 骨架图状态
class CustomItemPageInitial extends CustomItemPageState {}

/// 数据加载成功
class CustomItemPageLoadedState extends CustomItemPageState {
final List<Map<String, dynamic>> model;

CustomItemPageLoadedState({this.model});
}

/// 初始化失败
class CustomItemPageInitErrorState extends CustomItemPageState {}

/// 下拉刷新成功
class CustomItemPageRefreshSuccessState extends CustomItemPageState {}

/// 下拉刷新失败
class CustomItemPageRefreshErrorState extends CustomItemPageState {}

/// 上拉更多成功
class CustomItemPageLoadSuccessState extends CustomItemPageState {}

/// 上拉更多失败
class CustomItemPageLoadErrorState extends CustomItemPageState {}

/// 其他错误
class CustomItemPageErrorState extends CustomItemPageState {}

+ 22
- 6
lib/pages/custom_page/bloc/custom_page_repository.dart View File

@@ -8,12 +8,16 @@ class CustomPageRepository {
/// 初始化 /// 初始化
Future<List<Map<String, dynamic>>> fetchInitData() async { Future<List<Map<String, dynamic>>> fetchInitData() async {
try { try {
String skipIdentifier = !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER])
? data[GlobalConfig.SKIP_IDENTIFIER]
: null;
String skipIdentifier =
!EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) ? data[GlobalConfig.SKIP_IDENTIFIER] : null;
if (!EmptyUtil.isEmpty(skipIdentifier)) { if (!EmptyUtil.isEmpty(skipIdentifier)) {
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET);
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {}
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true);
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
List mobList = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']);
if (!EmptyUtil.isEmpty(mobList)) {
return mobList.map((e) => Map<String, dynamic>.from(e)).toList();
}
}
} }
} catch (e, s) { } catch (e, s) {
Logger.error(e, s); Logger.error(e, s);
@@ -23,7 +27,19 @@ class CustomPageRepository {


/// 缓存数据 /// 缓存数据
Future<List<Map<String, dynamic>>> fetchCacheData() async { Future<List<Map<String, dynamic>>> fetchCacheData() async {
try {} catch (e, s) {
try {
String skipIdentifier =
!EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) ? data[GlobalConfig.SKIP_IDENTIFIER] : null;
if (!EmptyUtil.isEmpty(skipIdentifier)) {
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier');
if (!EmptyUtil.isEmpty(result)) {
List mobList = result['mod_list'];
if (!EmptyUtil.isEmpty(mobList)) {
return mobList.map((e) => Map<String, dynamic>.from(e)).toList();
}
}
}
} catch (e, s) {
Logger.error(e, s); Logger.error(e, s);
} }
return null; return null;


+ 7
- 1
lib/pages/custom_page/bloc/custom_page_state.dart View File

@@ -1,7 +1,11 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:equatable/equatable.dart';


@immutable @immutable
abstract class CustomPageState {}
abstract class CustomPageState extends Equatable{
@override
List<Object> get props => [];
}


/// 初始化 /// 初始化
class CustomPageInitialState extends CustomPageState {} class CustomPageInitialState extends CustomPageState {}
@@ -10,6 +14,8 @@ class CustomPageInitialState extends CustomPageState {}
class CustomPageLoadedState extends CustomPageState { class CustomPageLoadedState extends CustomPageState {
List<Map<String, dynamic>> model; List<Map<String, dynamic>> model;
CustomPageLoadedState({this.model}); CustomPageLoadedState({this.model});
@override
List<Object> get props => [this.model];
} }


/// 刷新成功 /// 刷新成功


+ 188
- 0
lib/pages/custom_page/custom_item_page.dart View File

@@ -0,0 +1,188 @@
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:provider/provider.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart';
import 'package:zhiying_base_widget/widgets/refresh/refresh_footer/refresh_footer.dart';
import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_header.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'bloc/custom_item_page_bloc.dart';
import 'bloc/custom_item_page_state.dart';
import 'bloc/custom_item_page_event.dart';
import 'bloc/custom_item_page_repository.dart';

///
/// 通用模块的分类导航下的子模块
///
///
class CustomItemPage extends StatelessWidget {
final Map<String, dynamic> data;
final int tabIndex;
final String modPid;
final String modId;

CustomItemPage(this.data, this.tabIndex, this.modId, this.modPid);

@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: MainPageNotifier()),
],
child: BlocProvider<CustomItemPageBloc>(
create: (_) => CustomItemPageBloc(CustomItemPageRepository(this.data, this.tabIndex, this.modId, this.modPid)),
child: _CustomItemPageContainer(
this.data,
this.tabIndex,
this.modId,
this.modPid,
key: UniqueKey(),
),
),
);
}
}

class _CustomItemPageContainer extends StatefulWidget {
final Map<String, dynamic> data;
final int tabIndex;
final String modPid;
final String modId;

const _CustomItemPageContainer(this.data, this.tabIndex, this.modId, this.modPid, {Key key}) : super(key: key);

@override
__CustomItemPageContainerState createState() => __CustomItemPageContainerState();
}

class __CustomItemPageContainerState extends State<_CustomItemPageContainer> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;

ScrollController _controller;
RefreshController _refreshController;

/// 回到顶点
void _scrollTop() {
// _controller.jumpTo(0);
_controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear);
}

/// 初始化
void _initEvent() {
BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageInitEvent());
}

/// 刷新
void _refreshEvent() {
BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageRefreshEvent());
}

/// 下拉更多
void _loadEvent() {
// BlocProvider.of<CustomItemPageBloc>(context).add(CustomItemPageLoadEvent());
Provider.of<MainPageNotifier>(context, listen: false).loadMore();
Future.delayed(Duration(seconds: 1),()=> _refreshController?.loadComplete());
}

@override
void initState() {
_controller = ScrollController();
_refreshController = RefreshController(initialRefresh: false);
_initEvent();
super.initState();
}

@override
void dispose() {
_controller?.dispose();
_refreshController?.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return BlocConsumer<CustomItemPageBloc, CustomItemPageState>(
listener: (context, state) {},
buildWhen: (prev, current) {
if (current is CustomItemPageRefreshSuccessState) {
_refreshController?.refreshCompleted(resetFooterState: true);
return false;
}
if (current is CustomItemPageRefreshErrorState) {
_refreshController?.refreshFailed();
return false;
}
if (current is CustomItemPageLoadSuccessState) {
_refreshController?.loadComplete();
return false;
}
if (current is CustomItemPageLoadErrorState) {
_refreshController?.loadNoData();
return false;
}
if (current is CustomItemPageErrorState) {
return false;
}
return true;
},
builder: (context, state) {
if (state is CustomItemPageLoadedState) {
if (EmptyUtil.isEmpty(state.model))
return _buildEmptyWidget();
else
return _buildMainWidget(state.model);
}
if (state is CustomItemPageInitErrorState) {
return _buildEmptyWidget();
}
return _buildSkeletonWidget();
},
);
}

/// 有数据
Widget _buildMainWidget(final List<Map<String, dynamic>> model) {
return MediaQuery.removePadding(
context: context,
removeTop: true,
child: SmartRefresher(
controller: _refreshController,
enablePullDown: true,
enablePullUp: true,
onRefresh: _refreshEvent,
onLoading: _loadEvent,
header: RefreshHeader(),
footer: RefreshFooter(),
child: CustomScrollView(
controller: _controller,
slivers: _buildContentWidgets(model),
),
),
);
}

/// 根据widget的modName生成视图
List<Widget> _buildContentWidgets(final List<Map<String, dynamic>> datas) {
List<Widget> result = [];
for (int i = 0; i < datas.length; i++) {
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(datas[i]));
result.addAll(WidgetFactory.create(
item.modName,
isSliver: true,
model: datas[i],
));
}
return result;
}

/// 空数据
Widget _buildEmptyWidget() {
return Container();
}

/// 骨架图
Widget _buildSkeletonWidget() {
return Container();
}
}

+ 213
- 254
lib/pages/custom_page/custom_page.dart View File

@@ -1,17 +1,22 @@
import 'dart:convert';

import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:tab_indicator_styler/tab_indicator_styler.dart';
import 'package:zhiying_base_widget/pages/custom_page/custom_item_page.dart';
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart';
import 'package:zhiying_base_widget/widgets/custom/search/custom_search_widget.dart';
import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart';
import 'package:zhiying_base_widget/widgets/refresh/refresh_header/refresh_header.dart';
import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:zhiying_comm/util/custom_sliver_persistent_header_delegate.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/custom_page_bloc.dart'; import 'bloc/custom_page_bloc.dart';
import 'bloc/custom_page_state.dart'; import 'bloc/custom_page_state.dart';
import 'bloc/custom_page_event.dart'; import 'bloc/custom_page_event.dart';
import 'bloc/custom_page_repository.dart'; import 'bloc/custom_page_repository.dart';
import 'dart:ui'; import 'dart:ui';
import 'package:fluttertoast/fluttertoast.dart';


/// ///
/// 通用模块页面 /// 通用模块页面
@@ -24,55 +29,39 @@ class CustomPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// return NestedScrollDemoPage(); // return NestedScrollDemoPage();
return BlocProvider<CustomPageBloc>(
create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()),
child: _CommonPageContainer(),
// ),
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: MainPageBgNotifier()),
],
child: BlocProvider<CustomPageBloc>(
create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()),
child: _CommonPageContainer(data),
// ),
),
); );
} }
} }


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

_CommonPageContainer(this.data);

@override @override
__CommonPageContainerState createState() => __CommonPageContainerState(); __CommonPageContainerState createState() => __CommonPageContainerState();
} }


class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin { class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin {
ScrollController _controller;
ScrollController _controller2;
RefreshController _refreshController;
TabController _tabController; TabController _tabController;
bool _isEnded = false;

/// 回到顶点
void _scrollTop() {
// _controller.jumpTo(0);
_controller.animateTo(0, duration: Duration(milliseconds: 200), curve: Curves.linear);
}


/// 刷新 /// 刷新
void _onRefreshEvent() async { void _onRefreshEvent() async {
BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent()); BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent());
} }


/// 加载更多
void _onLoadEvent() async {}

@override
void initState() {
_controller = ScrollController();
_controller2 = ScrollController();
_refreshController = RefreshController(initialRefresh: false);
_tabController = TabController(length: 10, vsync: this);
super.initState();
}

@override @override
void dispose() { void dispose() {
_controller?.dispose();
_refreshController?.dispose();
_tabController?.dispose(); _tabController?.dispose();
_controller2?.dispose();
super.dispose(); super.dispose();
} }


@@ -87,244 +76,43 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single
return false; return false;
} }
if (current is CustomPageRefreshSuccessState) { if (current is CustomPageRefreshSuccessState) {
_refreshController.refreshCompleted(resetFooterState: true);
// _refreshController.refreshCompleted(resetFooterState: true);
return false; return false;
} }
if (current is CustomPageRefreshErrorState) { if (current is CustomPageRefreshErrorState) {
_refreshController.refreshFailed();
// _refreshController.refreshFailed();
return false; return false;
} }
return true; return true;
}, },
builder: (context, state) { builder: (context, state) {
// if (state is CustomPageLoadedState) {
// return _buildMain2Widget();
// }
// if (state is CustomPageInitErrorState) {
// return _buildMain2Widget();
// }
// return _buildMain2Widget();

return _buildMain2Widget();
},
),
);
}

/// 有数据
Widget _buildMainWidget() {
double top = MediaQueryData.fromWindow(window).padding.top;
return Scaffold(
backgroundColor: HexColor.fromHex('#F9F9F9'),
floatingActionButton: _buildFloatWidget(),
floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100),
body: SmartRefresher(
enablePullDown: true,
enablePullUp: false,
header: RefreshHeader(
offsetY: top,
),
controller: _refreshController,
onLoading: _onLoadEvent,
onRefresh: _onRefreshEvent,
child: CustomScrollView(
key: UniqueKey(),
controller: _controller,
slivers: [
/// 标题
SliverAppBar(
title: Text('标题'),
centerTitle: true,
pinned: true,
),

/// 有数据
if (state is CustomPageLoadedState) {
if (EmptyUtil.isEmpty(state.model)) return _buildEmptyWidget();
return _buildMainWidget(state.model);
}


/// 轮播图
_buildSliverBanner(),

/// 搜索
_buildSearch(),

/// TAB BAR
_buildTabbar(),

SliverFillRemaining(
child: TabBarView(
controller: _tabController,
children: List.generate(10, (index) => Container(
height: double.infinity,
width: double.infinity,
color: Colors.white,
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: CustomScrollView(
controller: _controller2,
key: UniqueKey(),
slivers: <Widget>[
_buildQucikEntry(),
_buildSearch(),
_buildSliverBanner(),
_buildGoodsList(),

],
),
),
)),
),
)
/// 初始化失败
if (state is CustomPageInitErrorState) {
return _buildEmptyWidget();
}


],
),
/// 骨架图
return _buildSkeletonWidget();
},
), ),
); );
} }


/// 有数据2
Widget _buildMain2Widget(){
/// 有数据
Widget _buildMainWidget(List<Map<String, dynamic>> model) {
return Scaffold( return Scaffold(
appBar: AppBar(title: Text('标题'),centerTitle: true,),
appBar: _buildAppbar(model?.first),
backgroundColor: HexColor.fromHex('#F9F9F9'), backgroundColor: HexColor.fromHex('#F9F9F9'),
floatingActionButton: _buildFloatWidget(),
// floatingActionButton: _buildFloatWidget(),
floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100), floatingActionButtonLocation: _CustomFloatingActionButtonLocation(FloatingActionButtonLocation.endFloat, 0, -100),
body: Column(
children: <Widget>[
Container(height: 40, width: double.infinity, color: Colors.green,),
Container(
height: 40,
width: double.infinity,
color: Colors.red,
child: TabBar(
isScrollable: true,
controller: _tabController,
tabs: List.generate(10, (index) => Text('$index')),
),
),
Expanded(
child: TabBarView(
controller: _tabController,
children: List.generate(10, (index) => Container(
height: double.infinity,
width: double.infinity,
color: Colors.white,
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: CustomScrollView(
controller: _controller,
key: UniqueKey(),
slivers: <Widget>[
_buildQucikEntry(),
_buildSearch(),
_buildSliverBanner(),
_buildSearch(title: '商品列表'),
_buildGoodsList(),

],
),
),
)),
),
)
],
),
);
}

/// tabBar
Widget _buildTabbar(){
return SliverPersistentHeader(
delegate: CustomSliverPersistentHeaderDelegate(
max: 40,
min: 40,
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.redAccent,
child: TabBar(
isScrollable: true,
controller: _tabController,
tabs: List.generate(10, (index) => Text('$index')),
),
),
),
pinned: true,
);
}

/// 多眼导航
Widget _buildQucikEntry(){
return SliverToBoxAdapter(
child: Container(
alignment: Alignment.center,
child: Text('多眼导航'),
height: 70,
width: double.infinity,
color: Colors.green,
),
);
}

/// 搜索
Widget _buildSearch({String title}){
return SliverPersistentHeader(
delegate: CustomSliverPersistentHeaderDelegate(
max: 40,
min: 40,
child: Container(
alignment: Alignment.center,
child: Text(title ?? '搜索'),
height: double.infinity,
width: double.infinity,
color: Colors.blueAccent,
),
),
pinned: true,
);
}

/// 商品列表
Widget _buildGoodsList(){
return SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
return Container(
height: 50,
width: double.infinity,
color: Colors.green[(index % 9 + 1) * 100],
);
}, childCount: 50));
}

/// 轮播图
Widget _buildSliverBanner(){
return SliverPersistentHeader(
delegate: CustomSliverPersistentHeaderDelegate(
max: 140,
min: 140,
child: Container(
child: Text('轮播图'),
alignment: Alignment.center,
height: double.infinity,
width: double.infinity,
color: Colors.yellowAccent,
),
),
pinned: false,
);
}

/// 悬浮按钮
Widget _buildFloatWidget() {
return Visibility(
visible: true,
child: GestureDetector(
onTap: ()=> _scrollTop(),
behavior: HitTestBehavior.opaque,
child: Container(
height: 30,
width: 30,
color: Colors.redAccent,
),
body: Column(
children: _buildFirstWidget(model),
), ),
); );
} }
@@ -350,8 +138,8 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single
onPressed: () => Navigator.maybePop(context), onPressed: () => Navigator.maybePop(context),
), ),
title: Text( title: Text(
'爆款',
style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 15, fontWeight: FontWeight.bold),
'',
style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 18, fontWeight: FontWeight.bold),
), ),
centerTitle: true, centerTitle: true,
elevation: 0, elevation: 0,
@@ -383,8 +171,179 @@ class __CommonPageContainerState extends State<_CommonPageContainer> with Single
], ],
)); ));
} }

/// 数据,生成第一层widget
List<Widget> _buildFirstWidget(List<Map<String, dynamic>> model) {
List<Widget> result = [];

// 分类导航的key ⚠️ 这里先写成Test 后续要改
const String CATEGORY_KEY = 'category_test';
// 判断是否有分类导航
// 判断最后一个是否属于分类导航,如果属于,则有分类导航,如果不是,则无分类导航
bool haveCategory = !EmptyUtil.isEmpty(model?.last) && model.last.containsKey('mod_name') && model.last['mod_name'] == CATEGORY_KEY;
int endIndexLength = model.length;
// 如果没有分类导航,则取分类导航之上的所有mod
if (!haveCategory) {
for (int i = 0; i < model.length; i++) {
Map<String, dynamic> item = model[i];
if (item['mod_name'] == CATEGORY_KEY) {
endIndexLength = (i + 1);
break;
}
}
}

for (int i = 0; i < endIndexLength; i++) {
WidgetModel item = WidgetModel.fromJson(Map<String, dynamic>.from(model[i]));
// last model
if (i == endIndexLength - 1) {
result.addAll(_buildTabBar(model[i]));
break;
}

// appBar 无需在这里添加
if (item.modName.contains('appbar')) {
continue;
}

result.addAll(WidgetFactory.create(
item.modName,
isSliver: false,
model: model[i],
));
}

return result;
}

/// appbar
Widget _buildAppbar(final Map<String, dynamic> model) {
if (EmptyUtil.isEmpty(model)) return null;
String mobName = model['mod_name'];
if (!mobName.contains('_appbar')) return null;
Map<String, dynamic> data = Map<String, dynamic>();
try {
data = jsonDecode(model['data']);
} catch (e, s) {
Logger.warn(e, s);
}

String parentTitle = !EmptyUtil.isEmpty(widget?.data) ? widget?.data['title_1'] ?? '' : '';

return AppBar(
backgroundColor: HexColor.fromHex(null != data ? data['app_bar_bg_color'] ?? '#FFFFFF' : '#FFFFFF'),
brightness: Brightness.light,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 22,
color: HexColor.fromHex('#333333'),
),
onPressed: () => Navigator.maybePop(context),
),
title: Text(
null != data && data.containsKey('app_bar_name') ? data['app_bar_name'] != '自定义页面' ? data['app_bar_name'] : parentTitle : parentTitle,
style: TextStyle(
color: HexColor.fromHex(null != data ? data['app_bar_name_color'] ?? '#333333' : '#333333'),
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
centerTitle: true,
elevation: 0,
);
}

/// tabBar
List<Widget> _buildTabBar(final Map<String, dynamic> model) {
Map<String, dynamic> data = Map<String, dynamic>();
List<Map<String, dynamic>> listStyle = [];
List<Widget> result = [];
try {
data = jsonDecode(model['data']);
listStyle = List.from(data['list_style']);
} catch (e, s) {
Logger.warn(e, s);
}

// 1、导航栏没开启的情况 传null进去进行获取没开启导航栏的widget集合
if (EmptyUtil.isEmpty(listStyle)) {
result.add(Expanded(
child: CustomItemPage(null, 0, model['mod_id']?.toString() ?? null, model['mod_pid']?.toString() ?? null),
));
return result;
}

// 2、导航栏开启的情况
if (listStyle.length > 0) {
// tabContorller 初始化
if (null == _tabController || _tabController.length != listStyle.length) {
_tabController = new TabController(length: listStyle.length, vsync: this);
}
result.add(Container(
height: 40,
width: double.infinity,
color: HexColor.fromHex('#FFFFFF'),
child: TabBar(
controller: _tabController,
isScrollable: /*listStyle.length <= 5 ? false : */ true,
labelColor: HexColor.fromHex('#FF4242'),
labelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
unselectedLabelColor: HexColor.fromHex('#999999'),
unselectedLabelStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
indicatorSize: TabBarIndicatorSize.label,
indicator: MaterialIndicator(
color: HexColor.fromHex('#FF4242'),
bottomLeftRadius: 1.25,
topLeftRadius: 1.25,
topRightRadius: 1.25,
bottomRightRadius: 1.25,
height: 2.5,
horizontalPadding: 5,
),
tabs: listStyle.map((e) => Text(e['name'])).toList(),
),
));

// 最后添加TabBarView
result.add(Expanded(
child: TabBarView(
controller: _tabController,
children: _buildTabBarViewChildren(listStyle, model['mod_id']?.toString(), model['mod_pid']?.toString()),
),
));
}
return result;
}

/// 返回TabBarView的视图
List<Widget> _buildTabBarViewChildren(final List<Map<String, dynamic>> listStyle, final String modId, final String modPid) {
List<Widget> result = [];
for (int i = 0; i < listStyle.length; i++) {
result.add(CustomItemPage(listStyle[i], i, modId, modPid));
}
return result;
}

// /// 悬浮按钮
// Widget _buildFloatWidget() {
// return Visibility(
// visible: true,
// child: GestureDetector(
// onTap: () => _scrollTop(),
// behavior: HitTestBehavior.opaque,
// child: Container(
// height: 30,
// width: 30,
// child: Icon(Icons.arrow_upward),
// ),
// ),
// );
// }

} }


/// 回到顶部的icon
class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation { class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation {
FloatingActionButtonLocation location; FloatingActionButtonLocation location;
double offsetX; // X方向的偏移量 double offsetX; // X方向的偏移量


+ 4
- 3
lib/pages/goods_details_page/goods_details_page.dart View File

@@ -8,6 +8,7 @@ import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_
import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/bloc/goods_details_page_repository.dart';
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page_sk.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page_sk.dart';
import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart';
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart';
import 'package:zhiying_base_widget/widgets/goods_details/appbar/goods_details_appbar_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/appbar/goods_details_appbar_widget.dart';
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart';
import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:zhiying_comm/zhiying_comm.dart';
@@ -35,7 +36,7 @@ class _GoodsDetailsPageState extends State<GoodsDetailsPage> {
return MultiProvider( return MultiProvider(
providers: [ providers: [
/// 滑动通知 /// 滑动通知
ChangeNotifierProvider.value(value: GoodsDetailsPageNotifier()),
ChangeNotifierProvider.value(value: MainPageNotifier()),
ChangeNotifierProvider.value(value: GoodsDetailsAppBarColorNotifier()), ChangeNotifierProvider.value(value: GoodsDetailsAppBarColorNotifier()),
], ],
child: BlocProvider<GoodsDetailsPageBloc>( child: BlocProvider<GoodsDetailsPageBloc>(
@@ -83,10 +84,10 @@ class _GoodsDetailsContainerState extends State<GoodsDetailsContainer> {
if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) { if (_controller.offset >= _controller.position.maxScrollExtent && !_isEnded) {
// 滑动到底部 // 滑动到底部
_isEnded = true; _isEnded = true;
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).loadMore();
Provider.of<MainPageNotifier>(context, listen: false).loadMore();
} else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) { } else if (_controller.offset < _controller.position.maxScrollExtent && _isEnded) {
_isEnded = false; _isEnded = false;
Provider.of<GoodsDetailsPageNotifier>(context, listen: false).reset();
Provider.of<MainPageNotifier>(context, listen: false).reset();
} }


if (_controller.offset >= 0 && _controller.offset <= BANNER_HEIGHT) { if (_controller.offset >= 0 && _controller.offset <= BANNER_HEIGHT) {


+ 14
- 14
lib/pages/goods_details_page/notifier/goods_details_page_notifier.dart View File

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


class GoodsDetailsPageNotifier with ChangeNotifier {
bool scrollEnd = false;
// 加载更多数据
void loadMore() {
scrollEnd = true;
notifyListeners();
}
void reset() {
scrollEnd = false;
notifyListeners();
}
}
// class GoodsDetailsPageNotifier with ChangeNotifier {
// bool scrollEnd = false;
//
// // 加载更多数据
// void loadMore() {
// scrollEnd = true;
// notifyListeners();
// }
//
// void reset() {
// scrollEnd = false;
// notifyListeners();
// }
// }

+ 3
- 3
lib/pages/main_page/main_page.dart View File

@@ -173,9 +173,9 @@ class _MainPageContainerState extends State<_MainPageContainer> {
list.add(SliverToBoxAdapter( list.add(SliverToBoxAdapter(
child: Container( child: Container(
height: 200, height: 200,
child: Center(
child: Text('暂时无数据哦~'),
),
// child: Center(
// child: Text('暂时无数据哦~'),
// ),
), ),
)); ));
} }


lib/widgets/custom/tabbar/custom_tabbar_widget.dart → lib/pages/main_page/main_page_skeleton.dart View File

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



/// ///
/// 通用模块的tabbar
/// 首页的骨架图
/// ///
class CustomTabBarWidget extends StatelessWidget {
class MainPageSkeleton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container(); return Container();

+ 4
- 4
lib/pages/wechat_teacher_page/model/wechat_teacher_style_model.dart View File

@@ -265,16 +265,16 @@ class OfficalWxchat {
} }


class OfficalWxchatList { class OfficalWxchatList {
String type;
String index;
String text; String text;
String subText; String subText;
String wechatAccount; String wechatAccount;
String qrcode; String qrcode;


OfficalWxchatList({this.type, this.text, this.subText, this.wechatAccount, this.qrcode});
OfficalWxchatList({this.index, this.text, this.subText, this.wechatAccount, this.qrcode});


OfficalWxchatList.fromJson(Map<String, dynamic> json) { OfficalWxchatList.fromJson(Map<String, dynamic> json) {
type = json['type'];
index = json['index'];
text = json['text']; text = json['text'];
subText = json['sub_text']; subText = json['sub_text'];
wechatAccount = json['wechat_account']; wechatAccount = json['wechat_account'];
@@ -283,7 +283,7 @@ class OfficalWxchatList {


Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>(); final Map<String, dynamic> data = new Map<String, dynamic>();
data['type'] = this.type;
data['index'] = this.index;
data['text'] = this.text; data['text'] = this.text;
data['sub_text'] = this.subText; data['sub_text'] = this.subText;
data['wechat_account'] = this.wechatAccount; data['wechat_account'] = this.wechatAccount;


+ 18
- 6
lib/register.dart View File

@@ -30,6 +30,9 @@ import 'package:zhiying_base_widget/pages/team_page/team_page.dart';
import 'package:zhiying_base_widget/pages/webview/base_webview.dart'; import 'package:zhiying_base_widget/pages/webview/base_webview.dart';
import 'package:zhiying_base_widget/pages/wechat_teacher_page/wechat_teacher_page.dart'; import 'package:zhiying_base_widget/pages/wechat_teacher_page/wechat_teacher_page.dart';
import 'package:zhiying_base_widget/pages/withdraw_page/withdraw_page.dart'; import 'package:zhiying_base_widget/pages/withdraw_page/withdraw_page.dart';
import 'package:zhiying_base_widget/widgets/custom/multi_nav/custom_quick_entry.dart';
import 'package:zhiying_base_widget/widgets/custom/search/custom_search_widget.dart';
import 'package:zhiying_base_widget/widgets/custom/slide_banner/custom_slide_banner_creater.dart';
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_widget.dart';
import 'package:zhiying_base_widget/widgets/goods_details/price/goods_details_price_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/price/goods_details_price_widget.dart';
import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart'; import 'package:zhiying_base_widget/widgets/goods_details/slide_banner/goods_details_slide_banner_widget.dart';
@@ -233,15 +236,14 @@ class BaseWidgetRegister {


/// 可滚动banner /// 可滚动banner
WidgetFactory.regist('index_carousel', HomeSlideBannerCreater()); WidgetFactory.regist('index_carousel', HomeSlideBannerCreater());
/// 首页商品推荐列表
WidgetFactory.regist('index_recommend_list', GoodsListCreater()); WidgetFactory.regist('index_recommend_list', GoodsListCreater());


/// 首页快速入口 /// 首页快速入口
WidgetFactory.regist(
'multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model)));
WidgetFactory.regist('multi_nav', DefaultWidgetCreater((model) => HomeQuickEntry(model)));


/// 滚动公告 /// 滚动公告
WidgetFactory.regist('index_placard',
DefaultWidgetCreater((model) => HomeNoticeWidget(model)));
WidgetFactory.regist('index_placard', DefaultWidgetCreater((model) => HomeNoticeWidget(model)));


/// 不可以滚动banner /// 不可以滚动banner
WidgetFactory.regist('index_banner_one', HomeBannerCreater()); WidgetFactory.regist('index_banner_one', HomeBannerCreater());
@@ -261,8 +263,7 @@ class BaseWidgetRegister {
WidgetFactory.regist('search_index_host_keyword', WidgetFactory.regist('search_index_host_keyword',
DefaultWidgetCreater((model) => SearchHotTagWidget(model))); DefaultWidgetCreater((model) => SearchHotTagWidget(model)));
// // 历史搜索标签 // // 历史搜索标签
WidgetFactory.regist('search_index_history',
DefaultWidgetCreater((model) => SearchHistoryTagWidget(model)));
WidgetFactory.regist('search_index_history', DefaultWidgetCreater((model) => SearchHistoryTagWidget(model)));


/// ==================== 搜索结果页面 ==================== /// /// ==================== 搜索结果页面 ==================== ///
// 输入框 // 输入框
@@ -395,5 +396,16 @@ class BaseWidgetRegister {
DefaultWidgetCreater((model) => HotRankTableBar(model))); DefaultWidgetCreater((model) => HotRankTableBar(model)));
WidgetFactory.regist('hot_rank_tab_view', WidgetFactory.regist('hot_rank_tab_view',
DefaultWidgetCreater((model) => HotRankingList(model))); DefaultWidgetCreater((model) => HotRankingList(model)));


/// ==================== 通用模块 ==================== ///
// 搜索
WidgetFactory.regist('search_test', DefaultWidgetCreater((model) => CustomSearchWidget(model)));
// 轮播广告位, 可滑动
WidgetFactory.regist('carousel_test', CustomSlideBannerCreater());
// 多眼导航,可滑动
WidgetFactory.regist('multi_nav_test', DefaultWidgetCreater((model) => CustomQuickEntry(model)));
// 商品列表
WidgetFactory.regist('product_test', GoodsDetailCommendCreater());
} }
} }

+ 0
- 16
lib/widgets/custom/appbar/custom_appbar_creater.dart View File

@@ -1,16 +0,0 @@
import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:flutter/material.dart';

import 'custom_appbar_widget.dart';

class CustomAppBarCreater extends WidgetCreater {
@override
List<Widget> createWidgets(Map<String, dynamic> model) {
return [CustomAppBarWidget(model)];
}

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

+ 0
- 45
lib/widgets/custom/appbar/custom_appbar_widget.dart View File

@@ -1,45 +0,0 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

///
/// 通用模块的AppBar Widget
///
class CustomAppBarWidget extends StatelessWidget {
final Map<String, dynamic> data;
Map<String, dynamic> model;

CustomAppBarWidget(this.data, {Key key}) : super(key: key) {
try {
var dataItem = data['data'];
if (!EmptyUtil.isEmpty(dataItem)) {
model = dataItem is Map ? dataItem : dataItem is String ? jsonDecode(dataItem) : null;
}
} catch (e, s) {
Logger.error(e, s);
}
}

@override
Widget build(BuildContext context) {
return SliverAppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 22,
color: HexColor.fromHex( '#333333'),
),
onPressed: () => Navigator.maybePop(context),
),
title: Text(
'自定义页面',
style: TextStyle(
fontSize: 15,
color: HexColor.fromHex('#333333'),
fontWeight: FontWeight.bold,
),
),
);
}
}

+ 4
- 0
lib/widgets/custom/multi_nav/bloc/bloc.dart View File

@@ -0,0 +1,4 @@
export 'custom_quick_entry_bloc.dart';
export 'custom_quick_entry_event.dart';
export 'custom_quick_entry_state.dart';
export 'custom_quick_entry_repository.dart';

+ 50
- 0
lib/widgets/custom/multi_nav/bloc/custom_quick_entry_bloc.dart View File

@@ -0,0 +1,50 @@
import 'dart:async';
import 'dart:math';

import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:zhiying_comm/util/empty_util.dart';

import './bloc.dart';

class CustomQuickEntryBloc extends Bloc<CustomQuickEntryEvent, CustomQuickEntryState> {
CustomQuickEntryRepository repository;

CustomQuickEntryBloc({@required this.repository});

@override
CustomQuickEntryState get initialState => InitialCustomQuickEntryState();

@override
Stream<CustomQuickEntryState> mapEventToState(CustomQuickEntryEvent event) async* {
/// 初始化
if (event is CustomQuickEntryInitEvent) {
yield* _mapHomeQuickEntryInitToState(event);
}
}

/// 初始化
Stream<CustomQuickEntryState> _mapHomeQuickEntryInitToState(CustomQuickEntryInitEvent event) async* {
/// 获取父页面传进来的数据
var parentData = await repository.fetchPreantData(event: event);
if (!EmptyUtil.isEmpty(parentData)) {
yield CustomQuickEntryLoadedState(model: parentData);
} else {
yield CustomQuickEntryErrorState();
}

// /// 获取本地缓存数据
// var cached = await repository.fetchCachedData(event: event);
// if (!EmptyUtil.isEmpty(cached)) {
// yield CustomQuickEntryCachedState(model: cached);
// }
//
// /// 获取网络的数据
// var result = await repository.fetchData(event: event);
// if (!EmptyUtil.isEmpty(result)) {
// yield CustomQuickEntryLoadedState(model: result);
// } else {
// yield CustomQuickEntryErrorState();
// }
}
}

+ 18
- 0
lib/widgets/custom/multi_nav/bloc/custom_quick_entry_event.dart View File

@@ -0,0 +1,18 @@
import 'package:equatable/equatable.dart';

abstract class CustomQuickEntryEvent extends Equatable {
const CustomQuickEntryEvent();

@override
List<Object> get props => [];
}

/// 初始事件
class CustomQuickEntryInitEvent extends CustomQuickEntryEvent {
final Map<String, dynamic> model;

const CustomQuickEntryInitEvent({this.model});

@override
List<Object> get props => [this.model];
}

+ 75
- 0
lib/widgets/custom/multi_nav/bloc/custom_quick_entry_repository.dart View File

@@ -0,0 +1,75 @@
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:zhiying_base_widget/widgets/custom/multi_nav/model/custom_quick_entry_model.dart';
import 'package:zhiying_comm/util/net_util.dart';
import 'package:zhiying_comm/util/empty_util.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

import 'custom_quick_entry_event.dart';

class CustomQuickEntryRepository {
/// 获取数据
Future<CustomQuickEntryModel> fetchData({@required CustomQuickEntryInitEvent event}) async {
try {
var result = await NetUtil.post('/api/v1/mod/${event.model['mod_id']}',
params: {
'ids': [event.model['mod_id']]
},
cache: true,
method: NetMethod.GET);

if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
Map<String, dynamic> data = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA];
return _getHomeQuickEntryModel(data);
}
} catch (e, s) {
Logger.error(e, s);
}

return null;
}

/// 获取父页面传进来的数据
Future<CustomQuickEntryModel> fetchPreantData({@required CustomQuickEntryInitEvent event}) async {
try {
String jsonStr = event.model['data'];
return CustomQuickEntryModel.fromJson(json.decode(jsonStr));
} catch (e, s) {
Logger.error(e, s);
}
return null;
}

/// 获取缓存数据
Future<CustomQuickEntryModel> fetchCachedData({@required CustomQuickEntryInitEvent event}) async {
try {
var result = await NetUtil.getRequestCachedData('/api/v1/mod/${event.model['mod_id']}', params: {
'ids': [event.model['mod_id']]
});
if (!EmptyUtil.isEmpty(result)) {
return _getHomeQuickEntryModel(result);
}
} catch (e, s) {
Logger.error(e, s);
}
return null;
}

CustomQuickEntryModel _getHomeQuickEntryModel(var data) {
try {
if (!EmptyUtil.isEmpty(data) && !EmptyUtil.isEmpty(data['data'])) {
var jsonData = jsonDecode(data['data']);
if (!EmptyUtil.isEmpty(jsonData)) {
CustomQuickEntryModel model = CustomQuickEntryModel.fromJson(jsonData);
if (null != model) {
return model;
}
}
}
} catch (e) {
Logger.log(e);
}
return null;
}
}

+ 40
- 0
lib/widgets/custom/multi_nav/bloc/custom_quick_entry_state.dart View File

@@ -0,0 +1,40 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:zhiying_base_widget/widgets/custom/multi_nav/model/custom_quick_entry_model.dart';


abstract class CustomQuickEntryState extends Equatable {
const CustomQuickEntryState();

@override
List<Object> get props => [];
}

/// 初始化状态
class InitialCustomQuickEntryState extends CustomQuickEntryState {
@override
List<Object> get props => [];
}

/// 加载数据完毕
class CustomQuickEntryLoadedState extends CustomQuickEntryState {
final CustomQuickEntryModel model;

const CustomQuickEntryLoadedState({@required this.model});

@override
List<Object> get props => [this.model];
}

/// 加载缓存数据
class CustomQuickEntryCachedState extends CustomQuickEntryState {
final CustomQuickEntryModel model;

const CustomQuickEntryCachedState({@required this.model});

@override
List<Object> get props => [this.model];
}

/// 加载数据出错
class CustomQuickEntryErrorState extends CustomQuickEntryState {}

+ 18
- 0
lib/widgets/custom/multi_nav/cached_network_image_util.dart View File

@@ -0,0 +1,18 @@

import 'package:flutter/material.dart';

///
/// 图片工具类,隔离build
///
class CachedNetworkImageUtil extends StatelessWidget {
Widget child;
CachedNetworkImageUtil({this.child});

@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: child,
);
}
}


+ 373
- 0
lib/widgets/custom/multi_nav/custom_quick_entry.dart View File

@@ -0,0 +1,373 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'custom_quick_entry_sk.dart';
import 'model/custom_quick_entry_model.dart';
import 'bloc/bloc.dart';

class CustomQuickEntry extends StatelessWidget {
final Map<String, dynamic> model;

const CustomQuickEntry(this.model);

@override
Widget build(BuildContext context) {
return BlocProvider<CustomQuickEntryBloc>(
create: (_) => CustomQuickEntryBloc(repository: CustomQuickEntryRepository())..add(CustomQuickEntryInitEvent(model: model)),
child: _CustomQuickEntryContainer(model),
);
}
}

class _CustomQuickEntryContainer extends StatefulWidget {
final Map<String, dynamic> model;
_CustomQuickEntryContainer(this.model);
@override
__CustomQuickEntryContainerState createState() => __CustomQuickEntryContainerState();
}

class __CustomQuickEntryContainerState extends State<_CustomQuickEntryContainer> {
/// Icon点击事件
void _itemIconClick(ListStyle model) {
print("item type = ${model.skipIdentifier}");
// Navigator.push(context, CupertinoPageRoute(builder: (_) => CommonPage(null)));
RouterUtil.route(model, model.toJson(), context);
}

SwiperController _controller;

@override
void initState() {
_controller = SwiperController();
super.initState();
}

@override
void dispose() {
_controller?.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return BlocConsumer<CustomQuickEntryBloc, CustomQuickEntryState>(
listener: (context, state) {
},
buildWhen: (prev, current) {
return true;
},
builder: (context, state) {
if (state is CustomQuickEntryCachedState) {
return _getMainWidget(state.model);
}
if (state is CustomQuickEntryLoadedState) {
return _getMainWidget(state.model);
}
if(state is CustomQuickEntryErrorState){
return Container();
}
return CustomQuickEntrySkeleton();
},
);
}

Widget _getMainWidget(CustomQuickEntryModel model) {
// 数据总数
int totalDataSize = model?.listStyle?.length ?? 0;

// 展示的总行数
int totalRowSize = int.parse(model?.rowSize ?? '1');

// 展示的列数
int columSize = int.parse(model?.columnSize ?? '5');

// 图标的高度
double iconHeight = 40.0;
// 标题的高度
double titleHeight = 20.0;

// 子元素的高度
double itemHeight = iconHeight;

// 如果有一级标题
if (!EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1') {
itemHeight = iconHeight + titleHeight;
}

//如果有二级标题
if (!EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1') {
itemHeight = iconHeight + titleHeight * 2;
}

// 进度条的边距
double barMargin = 15.0;
// 总页数
int totalPage = totalDataSize % (totalRowSize * columSize) == 0 ? totalDataSize ~/ (totalRowSize * columSize) : (totalDataSize ~/ (totalRowSize * columSize)) + 1;

// 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度
double totalHeight = totalRowSize * (itemHeight + barMargin) + 4;
if (!EmptyUtil.isEmpty(model?.pagination) && model.pagination != 'type_null' /*model.pagination_open == '0'*/) {
totalHeight = totalRowSize * (itemHeight + barMargin);
}

return Container(
color: HexColor.fromHex(widget?.model['bg_color']),
child: Container(
margin: EdgeInsets.only(top: 15, bottom: totalPage > 1 ? 15 : 0),
height: totalHeight,
// 总体高度
width: double.infinity,
color: HexColor.fromHex(widget?.model['bg_color']),
child: Swiper(
controller: _controller,
itemCount: totalPage,
loop: false,
itemBuilder: (context, index) {
return Container(
height: double.infinity,
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 12.5),
child: _getPageWidget(
iconHeight: iconHeight,
titleHeight: titleHeight,
totalDataSize: totalDataSize,
totalPage: totalPage,
currentPage: index,
totalRowSize: totalRowSize,
columSize: columSize,
model: model,
itemHeight: itemHeight,
),
);
},
pagination: totalPage <= 1 ? null : _getSwiperPaginationContorl(model, totalPage),
),
),
);
}

/// 页的数据
Widget _getPageWidget(
{double titleHeight, double iconHeight, int totalPage, int currentPage, int columSize, int totalRowSize, int totalDataSize, CustomQuickEntryModel model, double itemHeight}) {
List rowList = [];
for (int i = 0; i < totalRowSize; i++) {
rowList.add(i);
}

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: rowList.map((currentRow) {
return Container(
padding: EdgeInsets.only(bottom: 15),
width: double.infinity,
child: _getRowWidget(
titleHeight: titleHeight,
iconHeight: iconHeight,
totalPage: totalPage,
currentPage: currentPage,
columSize: columSize,
totalRowSize: totalRowSize,
totalDataSize: totalDataSize,
model: model,
currentRow: currentRow,
itemHeight: itemHeight),
);
}).toList(),
);
}

/// 行的数据
Widget _getRowWidget(
{double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
double itemHeight}) {
List itemList = [];
for (int i = 0; i < columSize; i++) {
itemList.add(i);
}

return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: itemList.map((currentIndex) {
return _getColumWidget(
titleHeight: titleHeight,
iconHeight: iconHeight,
totalPage: totalPage,
currentPage: currentPage,
totalDataSize: totalDataSize,
columSize: columSize,
totalRowSize: totalRowSize,
model: model,
currentRow: currentRow,
currentColum: currentIndex,
itemHeight: itemHeight,
);
}).toList(),
);
}

/// item 的数据
Widget _getColumWidget({
double titleHeight,
double iconHeight,
int totalPage,
int currentPage,
int columSize,
int totalRowSize,
int totalDataSize,
CustomQuickEntryModel model,
int currentRow,
int currentColum,
double itemHeight,
}) {
// 当前index = 当前的页数+1 * 当前的行数 + 当前的列数
// int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize;
// int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize :
// currentColum + currentRow * columSize;

// 当前元素的下表 = 当前的列数 + 当前的行数 * 列数 + 当前的页数 * 当前的行数 + 当前的列数
int currentIndex = currentColum + currentRow * columSize + currentPage * totalRowSize * columSize;

// print('current Index sss = $currentIndex');

if (currentIndex >= totalDataSize) {
return Container(
height: itemHeight,
width: 60,
);
}

ListStyle item = model?.listStyle[currentIndex];

return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _itemIconClick(item),
child: Container(
height: itemHeight,
width: 60,
// color: Colors.red,
child: Column(
children: <Widget>[
/// 图标
MyNetWorkImage(item.img),

/// 一级标题
Visibility(
visible: !EmptyUtil.isEmpty(model?.isShowTitle) && model.isShowTitle == '1',
child: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(
item?.title ?? '',
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.titleColor)),
),
),
),

/// 二级标题
Visibility(
visible: !EmptyUtil.isEmpty(model?.isShowSubTitle) && model.isShowSubTitle == '1',
child: Padding(
padding: const EdgeInsets.only(top: 5),
child: Text(
item?.subTitle ?? '',
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.subTitleColor)),
),
),
)
],
),
),
);
}

/// 进度条
SwiperPagination _getSwiperPaginationContorl(CustomQuickEntryModel model, int pageCount) {
if (EmptyUtil.isEmpty(model?.pagination) || model.pagination == 'type_null' /*model.pagination_open == '0'*/) {
return null;
}

if (model.pagination == 'type_point') {
// 点点点进度条
return _swiperPaginationDot(model);
} else {
// 自定义进度条
return _swiperCustomPagination(pageCount);
}
}

// 进度条 圆形
SwiperPagination _swiperPaginationDot(CustomQuickEntryModel model) {
return SwiperPagination(
margin: const EdgeInsets.only(),
builder: DotSwiperPaginationBuilder(color: HexColor.fromHex(model?.paginationUnselectColor), activeColor: HexColor.fromHex(model?.paginationSelectColor), size: 8, activeSize: 8));
}

// 自定义进度条 条形
SwiperPlugin _swiperCustomPagination(int pageCount) {
List list = [];
for (int i = 0; i < pageCount; i++) {
list.add(i);
}

return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) {
return Align(
alignment: Alignment(0.0, 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: list.map((index) {
var borderRadius;
if (index == 0) {
borderRadius = BorderRadius.only(topLeft: Radius.circular(2), bottomLeft: Radius.circular(2));
}
if (index == list.length - 1) {
borderRadius = BorderRadius.only(topRight: Radius.circular(2), bottomRight: Radius.circular(2));
}

if (index == config.activeIndex) {
borderRadius = BorderRadius.all(Radius.circular(2));
}

return Container(
height: 4,
width: 25,
decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex('#FF4242') : HexColor.fromHex('#FFFFFF')),
);
}).toList(),
),
);
});
}
}

///
/// 图片build 优化
///
class MyNetWorkImage extends StatelessWidget {
final String imgUrl;
final double width;

const MyNetWorkImage(this.imgUrl, {this.width = 40});

@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: CachedNetworkImage(
width: width,
imageUrl: imgUrl,
),
);
}
}

+ 20
- 0
lib/widgets/custom/multi_nav/custom_quick_entry_creater.dart View File

@@ -0,0 +1,20 @@
import 'package:flutter/src/widgets/framework.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

import 'custom_quick_entry.dart';
import 'custom_quick_entry_sk.dart';

///
/// 快速入口
///
class CustomQuickEntryCreater extends WidgetCreater {
@override
List<Widget> createSkeleton(Map<String, dynamic> model) {
return [CustomQuickEntrySkeleton()];
}

@override
List<Widget> createWidgets(Map<String, dynamic> model) {
return [CustomQuickEntry(model)];
}
}

+ 53
- 0
lib/widgets/custom/multi_nav/custom_quick_entry_sk.dart View File

@@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';

class CustomQuickEntrySkeleton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 153,
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 5),
itemBuilder: (context, index) {
return CustomQuickEntrySkeletonItem(
index: index,
);
},
itemCount: 10,
),
);
}
}

class CustomQuickEntrySkeletonItem extends StatelessWidget {
final int index;

const CustomQuickEntrySkeletonItem({this.index});

@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: Shimmer.fromColors(
baseColor: Colors.grey[300],
highlightColor: Colors.grey[100],
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// 图片
Container(
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(20)),
height: 40,
width: 40,
),
SizedBox(height: 5),

// Container(height: 10.h, width: 40.w, color: Colors.white,),
],
),
));
}
}

+ 187
- 0
lib/widgets/custom/multi_nav/model/custom_quick_entry_model.dart View File

@@ -0,0 +1,187 @@
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomQuickEntryModel {
String name;
String desc;
String pagination;
String moduleType;
String moduleKey;
String isTopMargin;
String isLeftRightMargin;
String isShow;
String topMargin;
String leftRightMargin;
String rowSize;
String columnSize;
String isShowSubTitle;
String isShowTitle;
String isShowCornerIcon;
String isShowCategory;
String paginationSelectColor;
String paginationUnselectColor;
List<ListStyle> listStyle;
List<TypeList> typeList;
int moduleKeyId;
String titleColor;
String subTitleColor;

CustomQuickEntryModel({
this.name,
this.desc,
this.pagination,
this.moduleType,
this.moduleKey,
this.isTopMargin,
this.isLeftRightMargin,
this.isShow,
this.topMargin,
this.leftRightMargin,
this.rowSize,
this.isShowSubTitle,
this.isShowCornerIcon,
this.isShowCategory,
this.paginationSelectColor,
this.paginationUnselectColor,
this.listStyle,
this.typeList,
this.moduleKeyId,
this.titleColor,
this.subTitleColor,
this.columnSize,
this.isShowTitle,
});

CustomQuickEntryModel.fromJson(Map<String, dynamic> json) {
name = json['name']?.toString();
desc = json['desc']?.toString();
pagination = json['pagination']?.toString();
moduleType = json['module_type']?.toString();
moduleKey = json['module_key']?.toString();
isTopMargin = json['is_top_margin']?.toString();
isLeftRightMargin = json['is_left_right_margin']?.toString();
isShow = json['is_show']?.toString();
topMargin = json['top_margin']?.toString();
leftRightMargin = json['left_right_margin']?.toString();
rowSize = json['row_size']?.toString();
columnSize = json['column_size']?.toString() ?? '5';
isShowSubTitle = json['is_show_sub_title']?.toString();
isShowCornerIcon = json['is_show_corner_icon']?.toString();
isShowCategory = json['is_show_category']?.toString();
paginationSelectColor = json['pagination_select_color']?.toString();
paginationUnselectColor = json['pagination_unselect_color']?.toString();
if (json['list_style'] != null) {
listStyle = new List<ListStyle>();
json['list_style'].forEach((v) {
listStyle.add(new ListStyle.fromJson(v));
});
}
if (json['type_list'] != null) {
typeList = new List<TypeList>();
json['type_list'].forEach((v) {
typeList.add(new TypeList.fromJson(v));
});
}
moduleKeyId = json['module_key_id'];
titleColor = json['title_color'];
subTitleColor = json['sub_title_color'];
isShowTitle = '1';
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['desc'] = this.desc;
data['pagination'] = this.pagination;
data['module_type'] = this.moduleType;
data['module_key'] = this.moduleKey;
data['is_top_margin'] = this.isTopMargin;
data['is_left_right_margin'] = this.isLeftRightMargin;
data['is_show'] = this.isShow;
data['top_margin'] = this.topMargin;
data['left_right_margin'] = this.leftRightMargin;
data['row_size'] = this.rowSize;
data['column_size'] = this.columnSize;
data['is_show_sub_title'] = this.isShowSubTitle;
data['is_show_corner_icon'] = this.isShowCornerIcon;
data['is_show_category'] = this.isShowCategory;
data['pagination_select_color'] = this.paginationSelectColor;
data['pagination_unselect_color'] = this.paginationUnselectColor;
if (this.listStyle != null) {
data['list_style'] = this.listStyle.map((v) => v.toJson()).toList();
}
if (this.typeList != null) {
data['type_list'] = this.typeList.map((v) => v.toJson()).toList();
}
data['module_key_id'] = this.moduleKeyId;
data['title_color'] = this.titleColor;
data['sub_title_color'] = this.subTitleColor;
data['is_show_title'] = this.isShowTitle;
return data;
}
}

class ListStyle extends SkipModel {
String title;
String img;
String subTitle;
String typeListKey;
String rightIcon;
String requiredLogin;
String requiredTaobaoAuth;
String skipIdentifier;

ListStyle({
this.title,
this.img,
this.subTitle,
this.typeListKey,
this.rightIcon,
this.requiredLogin,
this.requiredTaobaoAuth,
this.skipIdentifier,
});

ListStyle.fromJson(Map<String, dynamic> json) {
super.fromJson(json);
title = json['title'];
img = json['img'];
subTitle = json['sub_title'];
typeListKey = json['type_list_key'];
rightIcon = json['right_icon'];
requiredLogin = json['required_login'];
requiredTaobaoAuth = json['required_taobao_auth'];
skipIdentifier = json['skip_identifier'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = super.toJson();
data['title'] = this.title;
data['img'] = this.img;
data['sub_title'] = this.subTitle;
data['type_list_key'] = this.typeListKey;
data['right_icon'] = this.rightIcon;
data['required_login'] = this.requiredLogin;
data['required_taobao_auth'] = this.requiredTaobaoAuth;
data['skip_identifier'] = this.skipIdentifier;
return data;
}
}

class TypeList {
String name;
String key;

TypeList({this.name, this.key});

TypeList.fromJson(Map<String, dynamic> json) {
name = json['name'];
key = json['key'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['key'] = this.key;
return data;
}
}

+ 58
- 1
lib/widgets/custom/search/custom_search_widget.dart View File

@@ -1,13 +1,70 @@
import 'dart:convert';


import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:zhiying_base_widget/widgets/custom/search/model/custom_search_model.dart';
import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:zhiying_comm/zhiying_comm.dart';


/// ///
/// 通用模块的搜索栏 /// 通用模块的搜索栏
/// ///
class CustomSearchWidget extends StatelessWidget { class CustomSearchWidget extends StatelessWidget {
final Map<String, dynamic> data;
CustomSearchModel model;

CustomSearchWidget(this.data, {Key key}) : super(key: key) {
try {
model = CustomSearchModel.fromJson(jsonDecode(data['data']));
} catch (e, s) {
Logger.warn(e, s);
}
}

// 点击事件
void _onClickListener(BuildContext context, SkipModel skipModel) {
RouterUtil.route(skipModel, skipModel.toJson(), context);
}

@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container();
return _buildStyle1Widget(context);
}

/// 样式1
Widget _buildStyle1Widget(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => _onClickListener(context, model?.listStyle?.searchCss),
child: Container(
width: double.infinity,
decoration: BoxDecoration(color: HexColor.fromHex(model?.bgColor ?? '#FFFFFF')),
padding: const EdgeInsets.symmetric(horizontal: 12.5, vertical: 4),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(40),
color: HexColor.fromHex(model?.listStyle?.searchCss?.bgColor ?? '#F9F9F9'),
),
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
/// 搜索按钮
CachedNetworkImage(
imageUrl: model?.listStyle?.searchCss?.image ?? '',
height: 20,
width: 20,
),
const SizedBox(width: 7.5),

/// 提示文字
Text(
model?.listStyle?.searchCss?.text ?? '搜索更多优惠商品',
style: TextStyle(fontSize: 14, color: HexColor.fromHex(model?.listStyle?.searchCss?.textColor ?? '#999999')),
)
],
),
),
),
);
} }
} }

+ 157
- 0
lib/widgets/custom/search/model/custom_search_model.dart View File

@@ -0,0 +1,157 @@
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomSearchModel {
String name;
String desc;
String moduleType;
String moduleKey;
String isTopMargin;
String isLeftRightMargin;
String isShow;
String topMargin;
String leftRightMargin;
String bgColor;
ListStyle listStyle;

CustomSearchModel({
this.name,
this.desc,
this.moduleType,
this.moduleKey,
this.isTopMargin,
this.isLeftRightMargin,
this.isShow,
this.topMargin,
this.leftRightMargin,
this.bgColor,
this.listStyle,
});

CustomSearchModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
desc = json['desc'];
moduleType = json['module_type'];
moduleKey = json['module_key'];
isTopMargin = json['is_top_margin'];
isLeftRightMargin = json['is_left_right_margin'];
isShow = json['is_show'];
topMargin = json['top_margin'];
leftRightMargin = json['left_right_margin'];
bgColor = json['bg_color'];
listStyle = json['list_style'] != null ? new ListStyle.fromJson(json['list_style']) : null;
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['desc'] = this.desc;
data['module_type'] = this.moduleType;
data['module_key'] = this.moduleKey;
data['is_top_margin'] = this.isTopMargin;
data['is_left_right_margin'] = this.isLeftRightMargin;
data['is_show'] = this.isShow;
data['top_margin'] = this.topMargin;
data['left_right_margin'] = this.leftRightMargin;
data['bg_color'] = this.bgColor;
if (this.listStyle != null) {
data['list_style'] = this.listStyle.toJson();
}
return data;
}
}

class ListStyle {
SearchCss searchCss;
RightCss rightCss;

ListStyle({this.searchCss, this.rightCss});

ListStyle.fromJson(Map<String, dynamic> json) {
searchCss = json['search_css'] != null ? new SearchCss.fromJson(json['search_css']) : null;
rightCss = json['right_css'] != null ? new RightCss.fromJson(json['right_css']) : null;
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.searchCss != null) {
data['search_css'] = this.searchCss.toJson();
}
if (this.rightCss != null) {
data['right_css'] = this.rightCss.toJson();
}
return data;
}
}

class SearchCss extends SkipModel {
String name;
String text;
String image;
String bgColor;
String textColor;
String requiredLogin;
String requiredTaobaoAuth;
String skipIdentifier;

SearchCss({this.name, this.text, this.image, this.bgColor, this.textColor, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier});

SearchCss.fromJson(Map<String, dynamic> json) {
super.fromJson(json);
name = json['name'];
text = json['text'];
image = json['image'];
bgColor = json['bg_color'];
textColor = json['text_color'];
requiredLogin = json['required_login'];
requiredTaobaoAuth = json['required_taobao_auth'];
skipIdentifier = json['skip_identifier'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = super.toJson();
data['name'] = this.name;
data['text'] = this.text;
data['image'] = this.image;
data['bg_color'] = this.bgColor;
data['text_color'] = this.textColor;
data['required_login'] = this.requiredLogin;
data['required_taobao_auth'] = this.requiredTaobaoAuth;
data['skip_identifier'] = this.skipIdentifier;
return data;
}
}

class RightCss extends SkipModel {
String name;
String text;
String type;
String image;
String requiredLogin;
String requiredTaobaoAuth;
String skipIdentifier;

RightCss({this.name, this.text, this.type, this.image, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier});

RightCss.fromJson(Map<String, dynamic> json) {
super.fromJson(json);
name = json['name'];
text = json['text'];
type = json['type'];
image = json['image'];
requiredLogin = json['required_login'];
requiredTaobaoAuth = json['required_taobao_auth'];
skipIdentifier = json['skip_identifier'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = super.toJson();
data['name'] = this.name;
data['text'] = this.text;
data['type'] = this.type;
data['image'] = this.image;
data['required_login'] = this.requiredLogin;
data['required_taobao_auth'] = this.requiredTaobaoAuth;
data['skip_identifier'] = this.skipIdentifier;
return data;
}
}

+ 5
- 0
lib/widgets/custom/slide_banner/bloc/bloc.dart View File

@@ -0,0 +1,5 @@
export 'custom_slide_banner_bloc.dart';
export 'custom_slide_banner_event.dart';
export 'custom_slide_banner_state.dart';
export 'custom_slide_banner_repository.dart';
export '../model/custom_slide_banner_model.dart';

+ 43
- 0
lib/widgets/custom/slide_banner/bloc/custom_slide_banner_bloc.dart View File

@@ -0,0 +1,43 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';

import 'package:zhiying_comm/util/empty_util.dart';
import './bloc.dart';

class CustomSlideBannerBloc extends Bloc<CustomSlideBannerEvent, CustomSlideBannerState> {
CustomSlideBannerRepository repository;

CustomSlideBannerBloc({@required this.repository});

@override
CustomSlideBannerState get initialState => InitialCustomSlideBannerState();

@override
Stream<CustomSlideBannerState> mapEventToState(CustomSlideBannerEvent event) async* {
final currentState = state;

/// 初始化
if (event is CustomBannerInitEvent) {
print('---------HomeBannerInitEvent---------');
yield* _mapInitEventToState(event);
}
}

/// 初始化
Stream<CustomSlideBannerState> _mapInitEventToState(CustomBannerInitEvent event) async* {
var parent = await repository.fetchPreantData(event.model);
if (!EmptyUtil.isEmpty(parent)) {
yield HomeSlideBannerLoadedState(datas: parent);
return;
}
var cached = await repository.fetchCachedDate(id: event.model['mod_id']);
if (!EmptyUtil.isEmpty(cached)) yield CustomSlideBannerCachedState(datas: cached);
var param = await repository.fetchData(id: event.model['mod_id']);
if (!EmptyUtil.isEmpty(param))
yield HomeSlideBannerLoadedState(datas: param);
else
yield HomeSlideBannerLoadError();
}
}

+ 14
- 0
lib/widgets/custom/slide_banner/bloc/custom_slide_banner_event.dart View File

@@ -0,0 +1,14 @@
import 'package:equatable/equatable.dart';


abstract class CustomSlideBannerEvent extends Equatable {
const CustomSlideBannerEvent();
@override
List<Object> get props => [];
}

/// 初始事件
class CustomBannerInitEvent extends CustomSlideBannerEvent{
final Map<String, dynamic> model;
const CustomBannerInitEvent({this.model});
}

+ 45
- 0
lib/widgets/custom/slide_banner/bloc/custom_slide_banner_repository.dart View File

@@ -0,0 +1,45 @@
import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:zhiying_base_widget/widgets/custom/slide_banner/bloc/bloc.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomSlideBannerRepository {
/// 获取缓存数据
Future<CustomSlideBannerModel> fetchCachedDate({@required int id}) async {
var cached = await NetUtil.getRequestCachedData('/api/v1/mod', params: {
'ids': [id]
});
if (!EmptyUtil.isEmpty(cached)) {
try {
return CustomSlideBannerModel.fromJson(cached);
} catch (e) {}
}
return null;
}

/// 获取父页面传进来的数据
Future<CustomSlideBannerModel> fetchPreantData(@required Map<String, dynamic> model) async {
try {
if (!EmptyUtil.isEmpty(model)) {
return CustomSlideBannerModel.fromJson(jsonDecode(model['data']));
}
} catch (e) {}
return null;
}

/// 获取数据
Future<CustomSlideBannerModel> fetchData({@required int id}) async {
var params = await NetUtil.post('/api/v1/mod',
params: {
'ids': [id]
},
cache: true);
if (NetUtil.isSuccess(params) && !EmptyUtil.isEmpty(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {
try {
return CustomSlideBannerModel.fromJson(params[GlobalConfig.HTTP_RESPONSE_KEY_DATA]);
} catch (e) {}
}
return null;
}
}

+ 44
- 0
lib/widgets/custom/slide_banner/bloc/custom_slide_banner_state.dart View File

@@ -0,0 +1,44 @@
import 'package:equatable/equatable.dart';
import 'package:zhiying_base_widget/widgets/custom/slide_banner/model/custom_slide_banner_model.dart';

abstract class CustomSlideBannerState extends Equatable {
const CustomSlideBannerState();

@override
List<Object> get props => [];
}

/// 初始化状态
class InitialCustomSlideBannerState extends CustomSlideBannerState {
@override
List<Object> get props => [];
}

/// 缓存数据
class CustomSlideBannerCachedState extends CustomSlideBannerState {
CustomSlideBannerModel datas;

CustomSlideBannerCachedState({this.datas});

@override
List<Object> get props => [this.datas];
}

/// 数据加载完毕状态
class HomeSlideBannerLoadedState extends CustomSlideBannerState {
CustomSlideBannerModel datas;

HomeSlideBannerLoadedState({this.datas});

HomeSlideBannerLoadedState copyWith({CustomSlideBannerModel newData}) {
return HomeSlideBannerLoadedState(
datas: newData ?? datas,
);
}

@override
List<Object> get props => [datas];
}

/// 数据加载失败
class HomeSlideBannerLoadError extends CustomSlideBannerState {}

+ 224
- 0
lib/widgets/custom/slide_banner/custom_slide_banner.dart View File

@@ -0,0 +1,224 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:provider/provider.dart';
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_bg_notifier.dart';
import 'package:zhiying_comm/zhiying_comm.dart';
import 'bloc/bloc.dart';
import 'bloc/custom_slide_banner_repository.dart';
import 'custom_slide_banner_sk.dart';
import 'model/custom_slide_banner_model.dart';

///
/// 可滑动 banner 轮播图
///
class CustomSlideBanner extends StatefulWidget {
final Map<String, dynamic> model;

const CustomSlideBanner(this.model, {Key key}) : super(key: key);

@override
_CustomSlideBannerState createState() => _CustomSlideBannerState();
}

class _CustomSlideBannerState extends State<CustomSlideBanner> {
@override
Widget build(BuildContext context) {
return BlocProvider<CustomSlideBannerBloc>(
create: (_) => CustomSlideBannerBloc(repository: CustomSlideBannerRepository())..add(CustomBannerInitEvent(model: widget?.model)),
child: CustomSlideBannerContainer(),
);
}
}

class CustomSlideBannerContainer extends StatefulWidget {
@override
_CustomSlideBannerContainerState createState() => _CustomSlideBannerContainerState();
}

class _CustomSlideBannerContainerState extends State<CustomSlideBannerContainer> {
/// 子元素点击事件
void _itemOnClick(IndexCarouselList model) {
print('点击了 $model');
RouterUtil.route(model, model.toJson(), context);
// Navigator.push(context, CupertinoPageRoute(builder: (_) => VipCenterPage(null)));
}

SwiperController _swiperController;

@override
void initState() {
_swiperController = SwiperController();
super.initState();
}

@override
void dispose() {
_swiperController?.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return BlocConsumer<CustomSlideBannerBloc, CustomSlideBannerState>(
listener: (BuildContext context, CustomSlideBannerState state) {
if (state is HomeSlideBannerLoadError) {
print('数据加载出错');
}
},
buildWhen: (previous, current) {
/// 数据加载出错不进行build
if (current is HomeSlideBannerLoadError) {
return false;
}
return true;
},
builder: (context, state) {
print('currente state = $state');
if (state is HomeSlideBannerLoadedState) {
return _getMainWidget(state.datas);
}
if (state is CustomSlideBannerCachedState) {
return _getMainWidget(state.datas);
}
// 骨架屏
return CustomSlideBannerSkeleton();
},
);
}

Widget _getMainWidget(CustomSlideBannerModel datas) {
Future.delayed(Duration.zero, () {
Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container(
width: double.infinity,
height: 200,
color: Colors.redAccent,
));
});

int size = datas?.indexCarouselList?.length ?? 0;

return Container(
margin: EdgeInsets.all(10),
width: double.infinity,
height: 140,
child: Swiper(
controller: _swiperController,
itemBuilder: (BuildContext context, int index) {
IndexCarouselList items = datas.indexCarouselList[index];
return Container(
width: double.infinity,
decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5)),
child: ClipRRect(
borderRadius: BorderRadius.circular(7.5),
child: CachedNetworkImage(
imageUrl: items?.img ?? '',
fit: BoxFit.cover,
),
),
);
},
itemCount: size,
loop: size > 1 ,
autoplay: true,
onTap: (index) => _itemOnClick(datas.indexCarouselList[index]),
pagination: _getSwiperStyleByType(datas, size),
onIndexChanged: (index) {
// print('color = ${datas?.indexCarouselList[index]?.bgColor}');
Provider.of<MainPageBgNotifier>(context, listen: false).switchBg(Container(
width: double.infinity,
height: 200,
color: HexColor.fromHex(datas?.indexCarouselList[index]?.bgColor),
));
},
),
);
}

/// 获取进度样式
SwiperPlugin _getSwiperStyleByType(CustomSlideBannerModel model, int pageCount) {

// 一张图片就不滑动
if(pageCount <= 1){
return null;
}

if ('type_null' == model.pagination) {
return null;
}

if ('type_number' == model.pagination) {
return _getNumswiperPlugin(pageCount, model.paginationSelectColor, model.paginationUnselectColor);
}
if ('type_point' == model.pagination) {
return _swiperCustomPaginationDito(pageCount, model.paginationSelectColor, model.paginationUnselectColor);
}
if ('type_bar' == model.pagination) {
return _swiperCustomPagination(pageCount, model.paginationSelectColor, model.paginationUnselectColor);
}
return null;
}

/// 数字样式
SwiperPlugin _getNumswiperPlugin(int pageCount, String selectColor, String unselectColor) {
return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) {
return Align(
alignment: Alignment(0.9, 0.9),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 18),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(3), color: HexColor.fromHex('#80333333')),
child: RichText(
text: TextSpan(text: '${config.activeIndex + 1}', style: TextStyle(fontSize: 12, color: HexColor.fromHex(selectColor)), children: [
TextSpan(text: '/', style: TextStyle(fontSize: 12, color: HexColor.fromHex(unselectColor))),
TextSpan(text: '$pageCount', style: TextStyle(fontSize: 12, color: HexColor.fromHex(unselectColor))),
]),
)),
);
});
}

/// 自定义进度条
SwiperPlugin _swiperCustomPagination(int pageCount, String selectColor, String unselectColor) {
List list = [];
for (int i = 0; i < pageCount; i++) {
list.add(i);
}

return SwiperCustomPagination(builder: (BuildContext context, SwiperPluginConfig config) {
return Align(
alignment: Alignment(0.0, 0.9),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: list.map((index) {
var borderRadius;
if (index == 0) {
borderRadius = BorderRadius.only(topLeft: Radius.circular(2), bottomLeft: Radius.circular(2));
}
if (index == list.length - 1) {
borderRadius = BorderRadius.only(topRight: Radius.circular(2), bottomRight: Radius.circular(2));
}

if (index == config.activeIndex) {
borderRadius = BorderRadius.all(Radius.circular(2));
}

return Container(
height: 4,
width: 25,
decoration: BoxDecoration(borderRadius: borderRadius, color: index == config.activeIndex ? HexColor.fromHex(selectColor) : HexColor.fromHex(unselectColor)),
);
}).toList(),
),
);
});
}

/// 圆形进度条
SwiperPlugin _swiperCustomPaginationDito(int pageCount, String selectColor, String unselectColor) {
return SwiperPagination(
margin: const EdgeInsets.only(), builder: DotSwiperPaginationBuilder(color: HexColor.fromHex(unselectColor), activeColor: HexColor.fromHex(selectColor), size: 8, activeSize: 8));
}
}

+ 22
- 0
lib/widgets/custom/slide_banner/custom_slide_banner_creater.dart View File

@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:zhiying_comm/zhiying_comm.dart';

import 'custom_slide_banner.dart';
import 'custom_slide_banner_sk.dart';

///
/// 可以滚动Banner
///
class CustomSlideBannerCreater extends WidgetCreater {
@override
List<Widget> createSkeleton(Map<String, dynamic> model) {
return [CustomSlideBannerSkeleton()];
}

@override
List<Widget> createWidgets(Map<String, dynamic> model) {
return [
CustomSlideBanner(model),
];
}
}

+ 21
- 0
lib/widgets/custom/slide_banner/custom_slide_banner_sk.dart View File

@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:shimmer/shimmer.dart';

class CustomSlideBannerSkeleton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 200,
color: Colors.white,
child: Shimmer.fromColors(
baseColor: Colors.grey[300],
highlightColor: Colors.grey[100],
child: Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(10))),
),
),
);
}
}

+ 126
- 0
lib/widgets/custom/slide_banner/model/custom_slide_banner_model.dart View File

@@ -0,0 +1,126 @@
import 'package:zhiying_comm/zhiying_comm.dart';

class CustomSlideBannerModel {
String name;
String desc;
String pagination;
String moduleType;
String moduleKey;
String isTopMargin;
String isLeftRightMargin;
String isShow;
String carouselType;
String paginationSelectColor;
String paginationUnselectColor;
String barWidthHeightRatio;
String bgWidthHeightRatio;
String carouselTime;
String topMargin;
String leftRightMargin;
List<IndexCarouselList> indexCarouselList;
int moduleKeyId;

CustomSlideBannerModel({
this.name,
this.desc,
this.pagination,
this.moduleType,
this.moduleKey,
this.isTopMargin,
this.isLeftRightMargin,
this.isShow,
this.carouselType,
this.paginationSelectColor,
this.paginationUnselectColor,
this.barWidthHeightRatio,
this.bgWidthHeightRatio,
this.carouselTime,
this.topMargin,
this.leftRightMargin,
this.indexCarouselList,
this.moduleKeyId,
});

CustomSlideBannerModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
desc = json['desc'];
pagination = json['pagination'];
moduleType = json['module_type'];
moduleKey = json['module_key'];
isTopMargin = json['is_top_margin'];
isLeftRightMargin = json['is_left_right_margin'];
isShow = json['is_show'];
carouselType = json['carousel_type'];
paginationSelectColor = json['pagination_select_color'];
paginationUnselectColor = json['pagination_unselect_color'];
barWidthHeightRatio = json['bar_width_height_ratio'];
bgWidthHeightRatio = json['bg_width_height_ratio'];
carouselTime = json['carousel_time'];
topMargin = json['top_margin'];
leftRightMargin = json['left_right_margin'];
if (json['index_carousel_list'] != null) {
indexCarouselList = new List<IndexCarouselList>();
json['index_carousel_list'].forEach((v) {
indexCarouselList.add(new IndexCarouselList.fromJson(v));
});
}
moduleKeyId = json['module_key_id'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['desc'] = this.desc;
data['pagination'] = this.pagination;
data['module_type'] = this.moduleType;
data['module_key'] = this.moduleKey;
data['is_top_margin'] = this.isTopMargin;
data['is_left_right_margin'] = this.isLeftRightMargin;
data['is_show'] = this.isShow;
data['carousel_type'] = this.carouselType;
data['pagination_select_color'] = this.paginationSelectColor;
data['pagination_unselect_color'] = this.paginationUnselectColor;
data['bar_width_height_ratio'] = this.barWidthHeightRatio;
data['bg_width_height_ratio'] = this.bgWidthHeightRatio;
data['carousel_time'] = this.carouselTime;
data['top_margin'] = this.topMargin;
data['left_right_margin'] = this.leftRightMargin;
if (this.indexCarouselList != null) {
data['index_carousel_list'] = this.indexCarouselList.map((v) => v.toJson()).toList();
}
data['module_key_id'] = this.moduleKeyId;
return data;
}
}

class IndexCarouselList extends SkipModel {
String name;
String img;
String bgColor;
String requiredLogin;
String requiredTaobaoAuth;
String skipIdentifier;

IndexCarouselList({this.name, this.img, this.bgColor, this.requiredLogin, this.requiredTaobaoAuth, this.skipIdentifier});

IndexCarouselList.fromJson(Map<String, dynamic> json) {
super.fromJson(json);
name = json['name'];
img = json['img'];
bgColor = json['bg_color'];
requiredLogin = json['required_login'];
requiredTaobaoAuth = json['required_taobao_auth'];
skipIdentifier = json['skip_identifier'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = super.toJson();
data['name'] = this.name;
data['img'] = this.img;
data['bg_color'] = this.bgColor;
data['required_login'] = this.requiredLogin;
data['required_taobao_auth'] = this.requiredTaobaoAuth;
data['skip_identifier'] = this.skipIdentifier;
return data;
}
}

+ 10
- 8
lib/widgets/goods_details/recommend/goods_detail_commend_list.dart View File

@@ -4,11 +4,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart'; import 'package:zhiying_base_widget/pages/goods_details_page/notifier/goods_details_page_notifier.dart';
import 'package:zhiying_base_widget/pages/main_page/notifier/main_page_notifier.dart';
import 'package:zhiying_base_widget/widgets/home/home_goods/bloc/home_goods_bloc.dart'; import 'package:zhiying_base_widget/widgets/home/home_goods/bloc/home_goods_bloc.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.dart';
import 'package:zhiying_base_widget/widgets/home/home_goods/home_goods_item_single.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_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/models/home_goods_style_model.dart';
import 'package:zhiying_base_widget/widgets/home/home_goods/skeleton/home_goods_sk.dart';
import 'package:zhiying_comm/util/base_bloc.dart'; import 'package:zhiying_comm/util/base_bloc.dart';


class GoodsDetailCommendList extends StatefulWidget { class GoodsDetailCommendList extends StatefulWidget {
@@ -40,16 +42,13 @@ class _GoodsDetailCommendListContainer extends StatefulWidget {
final Map<String, dynamic> data; final Map<String, dynamic> data;
final String provider; final String provider;


_GoodsDetailCommendListContainer(this.data, this.provider, {Key key})
: super(key: key);
_GoodsDetailCommendListContainer(this.data, this.provider, {Key key}) : super(key: key);


@override @override
_GoodsDetailCommendListContainerState createState() =>
_GoodsDetailCommendListContainerState();
_GoodsDetailCommendListContainerState createState() => _GoodsDetailCommendListContainerState();
} }


class _GoodsDetailCommendListContainerState
extends State<_GoodsDetailCommendListContainer> {
class _GoodsDetailCommendListContainerState extends State<_GoodsDetailCommendListContainer> {
HomeGoodsBloc _bloc; HomeGoodsBloc _bloc;
HomeGoodsStyleModel _style; HomeGoodsStyleModel _style;


@@ -70,8 +69,7 @@ class _GoodsDetailCommendListContainerState
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
print('didChangeDependencies'); print('didChangeDependencies');
bool isNeedLoadMore =
Provider.of<GoodsDetailsPageNotifier>(context).scrollEnd;
bool isNeedLoadMore = Provider.of<MainPageNotifier>(context).scrollEnd;
if (isNeedLoadMore && widget.provider != '') { if (isNeedLoadMore && widget.provider != '') {
print('HomeGoods loadmore...'); print('HomeGoods loadmore...');
_bloc.loadMore(widget.provider); _bloc.loadMore(widget.provider);
@@ -83,6 +81,10 @@ class _GoodsDetailCommendListContainerState
return StreamBuilder<List<HomeGoodsModel>>( return StreamBuilder<List<HomeGoodsModel>>(
stream: _bloc.outData, stream: _bloc.outData,
builder: (BuildContext context, AsyncSnapshot snapshot) { builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return SliverToBoxAdapter(child: HomeGoodsSkeleton());
}

List<HomeGoodsModel> goods = snapshot.data; List<HomeGoodsModel> goods = snapshot.data;
int column = 2; int column = 2;
int count = ((goods?.length ?? 0) / column).ceil(); int count = ((goods?.length ?? 0) / column).ceil();


+ 35
- 31
lib/widgets/goods_details/recommend/goods_detail_commend_widget.dart View File

@@ -8,9 +8,10 @@ import 'package:zhiying_comm/zhiying_comm.dart';


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

// Map<String, dynamic> style = {}; // Map<String, dynamic> style = {};
HomeGoodsStyleModel styleModel; HomeGoodsStyleModel styleModel;
GoodsDetailsRecommendWidget(this.data, {Key key}) : super(key: key) { GoodsDetailsRecommendWidget(this.data, {Key key}) : super(key: key) {
try { try {
styleModel = HomeGoodsStyleModel.fromJson(convert.jsonDecode(data['data'])); styleModel = HomeGoodsStyleModel.fromJson(convert.jsonDecode(data['data']));
@@ -47,36 +48,39 @@ class _GoodsDetailsRecommendWidgetState extends State<GoodsDetailsRecommendWidge
} }


Widget _createTitle() { Widget _createTitle() {
return Container(
width: double.infinity,
height: 50,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CachedNetworkImage(
// imageUrl: _style.recListIcon ?? '',
// imageUrl: widget?.style['rec_icon'] ?? '',
imageUrl: widget?.styleModel?.recIcon ?? '',
width: 15,
height: 15,
),
Padding(
padding: const EdgeInsets.only(left: 2.5),
child: Text(
// _style?.recListText ?? '',
// widget?.style['title'] ?? '',
widget?.styleModel?.title ?? '',
style: TextStyle(
// color: HexColor.fromHex(_style?.recListTextColor ?? 'FF4242'),
// color: HexColor.fromHex(widget?.style['title_color'] ?? ''),
color: HexColor.fromHex(widget?.styleModel?.titleColor ?? ''),
fontSize: 14,
),
if (EmptyUtil.isEmpty(widget?.styleModel?.title))
return Container();
else
return Container(
width: double.infinity,
height: 50,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CachedNetworkImage(
// imageUrl: _style.recListIcon ?? '',
// imageUrl: widget?.style['rec_icon'] ?? '',
imageUrl: widget?.styleModel?.recIcon ?? '',
width: 15,
height: 15,
), ),
)
],
),
);
Padding(
padding: const EdgeInsets.only(left: 2.5),
child: Text(
// _style?.recListText ?? '',
// widget?.style['title'] ?? '',
widget?.styleModel?.title ?? '',
style: TextStyle(
// color: HexColor.fromHex(_style?.recListTextColor ?? 'FF4242'),
// color: HexColor.fromHex(widget?.style['title_color'] ?? ''),
color: HexColor.fromHex(widget?.styleModel?.titleColor ?? ''),
fontSize: 14,
),
),
)
],
),
);
} }
} }

+ 1
- 1
lib/widgets/home/home_goods/home_goods.dart View File

@@ -99,7 +99,7 @@ class _HomeGoodsContainerState extends State<_HomeGoodsContainer> {
// } // }
Loading.dismiss(); Loading.dismiss();
List<HomeGoodsModel> goods = snapshot.data; List<HomeGoodsModel> goods = snapshot.data;
int column = int.tryParse(_style.listColumn);
int column = int.tryParse(_style.listColumn ?? '1');
column = column <= 0 ? 1 : column; column = column <= 0 ? 1 : column;
int count = ((goods?.length ?? 0) / column).ceil(); int count = ((goods?.length ?? 0) / column).ceil();
return SliverList( return SliverList(


+ 9
- 3
lib/widgets/home/home_slide_banner/home_slide_banner.dart View File

@@ -117,9 +117,15 @@ class _HomeSlideBannerContainerState extends State<HomeSlideBannerContainer> {
IndexCarousel items = datas.index_carousel_list[index]; IndexCarousel items = datas.index_carousel_list[index];
return Container( return Container(
width: double.infinity, width: double.infinity,
child: CachedNetworkImage(
imageUrl: items?.img ?? '',
fit: BoxFit.cover,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.5)
),
child: ClipRRect(
borderRadius: BorderRadius.circular(7.5),
child: CachedNetworkImage(
imageUrl: items?.img ?? '',
fit: BoxFit.cover,
),
), ),
); );
}, },


+ 3
- 0
lib/widgets/mine/mine_header/mine_header_container.dart View File

@@ -11,6 +11,9 @@ import 'package:zhiying_base_widget/widgets/mine/mine_header/model/mine_profile_
import 'package:zhiying_comm/util/base_bloc.dart'; import 'package:zhiying_comm/util/base_bloc.dart';
import 'package:zhiying_comm/zhiying_comm.dart'; import 'package:zhiying_comm/zhiying_comm.dart';


///
/// 我的页面:头部wiget
///
class MineHeaderContainer extends StatefulWidget { class MineHeaderContainer extends StatefulWidget {
final Map<String, dynamic> data; final Map<String, dynamic> data;
Map<String, dynamic> json; Map<String, dynamic> json;


Loading…
Cancel
Save