2、收藏夹首次打开黑色问题 3、反馈的假实现 4、商品分享的获取数据问题 5、搜索结果页 搜索页面的状态栏字体颜色 6、退出登录返回上一页tags/0.0.2+2^0
@@ -0,0 +1 @@ | |||||
с�Eг3}jB\В�^Q� |
@@ -9,6 +9,7 @@ import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_localizations/flutter_localizations.dart'; | import 'package:flutter_localizations/flutter_localizations.dart'; | ||||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | import 'package:pull_to_refresh/pull_to_refresh.dart'; | ||||
import 'package:zhiying_comm/util/update/app_update_util.dart'; | import 'package:zhiying_comm/util/update/app_update_util.dart'; | ||||
import 'package:jdsdk/jdsdk.dart'; | |||||
import 'util/localizations_delegate.dart'; | import 'util/localizations_delegate.dart'; | ||||
@@ -45,6 +46,8 @@ class _MyAppState extends State<MyApp> { | |||||
FlutterAlibc.initAlibc(version: "", appName: "").then((result) { | FlutterAlibc.initAlibc(version: "", appName: "").then((result) { | ||||
print("白川" + '${result.errorCode} ${result.errorMessage}'); | print("白川" + '${result.errorCode} ${result.errorMessage}'); | ||||
}); | }); | ||||
print('初始化京东~'); | |||||
Jdsdk.init(appKey: 'c0abbe1f201464ee139d613591a1be02', appSecret: 'a0eeac7105bf4c7cb573972aa03ed95c'); | |||||
// app更新插件 | // app更新插件 | ||||
AppUpdateUtil.initXUpdate(); | AppUpdateUtil.initXUpdate(); | ||||
} | } | ||||
@@ -0,0 +1,61 @@ | |||||
import 'dart:async'; | |||||
import 'package:bloc/bloc.dart'; | |||||
import 'custom_page_event.dart'; | |||||
import 'custom_page_repository.dart'; | |||||
import 'custom_page_state.dart'; | |||||
import 'package:zhiying_comm/util/empty_util.dart'; | |||||
class CustomPageBloc extends Bloc<CustomPageEvent, CustomPageState> { | |||||
// CommonBloc() : super(CommonInitial()); | |||||
CustomPageRepository repository; | |||||
CustomPageBloc(this.repository); | |||||
@override | |||||
CustomPageState get initialState => CustomPageInitialState(); | |||||
@override | |||||
Stream<CustomPageState> mapEventToState( | |||||
CustomPageEvent event, | |||||
) async* { | |||||
/// 初始化 | |||||
if (event is CustomPageInitEvent) { | |||||
yield* _mapInitToState(event); | |||||
} | |||||
/// 刷新 | |||||
if (event is CustomPageRefreshEvent) { | |||||
yield* _mapRefreshToState(event); | |||||
} | |||||
} | |||||
/// 刷新 | |||||
Stream<CustomPageState> _mapRefreshToState(CustomPageRefreshEvent event) async* { | |||||
var result = await repository.fetchInitData(); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield CustomPageRefreshSuccessState(); | |||||
yield CustomPageLoadedState(model: result); | |||||
} else { | |||||
yield CustomPageRefreshErrorState(); | |||||
yield CustomPageErrorState(); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<CustomPageState> _mapInitToState(CustomPageInitEvent event) async* { | |||||
// 获取缓存数据 | |||||
var cache = await repository.fetchCacheData(); | |||||
if (!EmptyUtil.isEmpty(cache) && cache is List) { | |||||
yield CustomPageLoadedState(model: cache); | |||||
} | |||||
// 获取网络数据 | |||||
var result = await repository.fetchInitData(); | |||||
if (!EmptyUtil.isEmpty(result) && result is List) { | |||||
yield CustomPageLoadedState(model: result); | |||||
} else { | |||||
yield CustomPageInitErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,10 @@ | |||||
import 'package:meta/meta.dart'; | |||||
@immutable | |||||
abstract class CustomPageEvent {} | |||||
/// 初始化 | |||||
class CustomPageInitEvent extends CustomPageEvent{} | |||||
/// 刷新 | |||||
class CustomPageRefreshEvent extends CustomPageEvent{} |
@@ -0,0 +1,31 @@ | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class CustomPageRepository { | |||||
Map<String, dynamic> data; | |||||
CustomPageRepository({this.data}); | |||||
/// 初始化 | |||||
Future<List<Map<String, dynamic>>> fetchInitData() async { | |||||
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.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) {} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 缓存数据 | |||||
Future<List<Map<String, dynamic>>> fetchCacheData() async { | |||||
try {} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
import 'package:meta/meta.dart'; | |||||
@immutable | |||||
abstract class CustomPageState {} | |||||
/// 初始化 | |||||
class CustomPageInitialState extends CustomPageState {} | |||||
/// 数据加载成功 | |||||
class CustomPageLoadedState extends CustomPageState { | |||||
List<Map<String, dynamic>> model; | |||||
CustomPageLoadedState({this.model}); | |||||
} | |||||
/// 刷新成功 | |||||
class CustomPageRefreshSuccessState extends CustomPageState{} | |||||
/// 刷新失败 | |||||
class CustomPageRefreshErrorState extends CustomPageState{} | |||||
/// 初始化失败 | |||||
class CustomPageInitErrorState extends CustomPageState {} | |||||
/// 数据加载失败 | |||||
class CustomPageErrorState extends CustomPageState {} |
@@ -0,0 +1,286 @@ | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:pull_to_refresh/pull_to_refresh.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:flutter/material.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 'bloc/custom_page_bloc.dart'; | |||||
import 'bloc/custom_page_state.dart'; | |||||
import 'bloc/custom_page_event.dart'; | |||||
import 'bloc/custom_page_repository.dart'; | |||||
import 'dart:ui'; | |||||
/// | |||||
/// 通用模块页面 | |||||
/// | |||||
class CustomPage extends StatelessWidget { | |||||
final Map<String, dynamic> data; | |||||
CustomPage(this.data, {Key key}) : super(key: key); | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
// return MultiProvider( | |||||
// providers: [], | |||||
// child: | |||||
return BlocProvider<CustomPageBloc>( | |||||
create: (_) => CustomPageBloc(CustomPageRepository(data: data))..add(CustomPageInitEvent()), | |||||
child: _CommonPageContainer(), | |||||
// ), | |||||
); | |||||
} | |||||
} | |||||
class _CommonPageContainer extends StatefulWidget { | |||||
@override | |||||
__CommonPageContainerState createState() => __CommonPageContainerState(); | |||||
} | |||||
class __CommonPageContainerState extends State<_CommonPageContainer> with SingleTickerProviderStateMixin { | |||||
ScrollController _controller; | |||||
RefreshController _refreshController; | |||||
TabController _tabController; | |||||
bool _isEnded = false; | |||||
/// 回到顶点 | |||||
void _scrollTop() { | |||||
// _controller.jumpTo(0); | |||||
_controller.animateTo(0, duration: Duration(seconds: 1), curve: Curves.linear); | |||||
} | |||||
/// 刷新 | |||||
void _onRefreshEvent() async { | |||||
BlocProvider.of<CustomPageBloc>(context).add(CustomPageRefreshEvent()); | |||||
} | |||||
/// 加载更多 | |||||
void _onLoadEvent() async {} | |||||
@override | |||||
void initState() { | |||||
_controller = ScrollController(); | |||||
_refreshController = RefreshController(initialRefresh: false); | |||||
_tabController = TabController(length: 10, vsync: this); | |||||
super.initState(); | |||||
} | |||||
@override | |||||
void dispose() { | |||||
_controller?.dispose(); | |||||
_refreshController?.dispose(); | |||||
_tabController?.dispose(); | |||||
super.dispose(); | |||||
} | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return MediaQuery.removePadding( | |||||
context: context, | |||||
child: BlocConsumer<CustomPageBloc, CustomPageState>( | |||||
listener: (context, state) {}, | |||||
buildWhen: (prev, current) { | |||||
if (current is CustomPageErrorState) { | |||||
return false; | |||||
} | |||||
if (current is CustomPageRefreshSuccessState) { | |||||
_refreshController.refreshCompleted(resetFooterState: true); | |||||
return false; | |||||
} | |||||
if (current is CustomPageRefreshErrorState) { | |||||
_refreshController.refreshFailed(); | |||||
return false; | |||||
} | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
if (state is CustomPageLoadedState) { | |||||
return _buildMainWidget(); | |||||
} | |||||
if (state is CustomPageInitErrorState) { | |||||
return _buildMainWidget(); | |||||
} | |||||
return _buildSkeletonWidget(); | |||||
}, | |||||
), | |||||
); | |||||
} | |||||
/// 有数据 | |||||
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: false, | |||||
enablePullUp: false, | |||||
header: RefreshHeader( | |||||
offsetY: top, | |||||
), | |||||
controller: _refreshController, | |||||
onLoading: _onLoadEvent, | |||||
onRefresh: _onRefreshEvent, | |||||
child: CustomScrollView( | |||||
controller: _controller, | |||||
slivers: [ | |||||
/// 标题 | |||||
SliverAppBar( | |||||
title: Text('标题'), | |||||
centerTitle: true, | |||||
pinned: true, | |||||
), | |||||
/// 搜索 | |||||
SliverPersistentHeader( | |||||
delegate: CustomSliverPersistentHeaderDelegate( | |||||
max: 40, | |||||
min: 40, | |||||
child: Container( | |||||
height: double.infinity, | |||||
width: double.infinity, | |||||
color: Colors.yellowAccent, | |||||
), | |||||
), | |||||
// pinned: true, | |||||
), | |||||
/// TAB BAR | |||||
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, | |||||
), | |||||
/// 轮播图 | |||||
SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 140, | |||||
width: double.infinity, | |||||
color: Colors.blueAccent, | |||||
), | |||||
), | |||||
/// 多眼导航 | |||||
SliverToBoxAdapter( | |||||
child: Container( | |||||
height: 70, | |||||
width: double.infinity, | |||||
color: Colors.yellowAccent, | |||||
), | |||||
), | |||||
/// 商品列表 | |||||
SliverList( | |||||
delegate: SliverChildBuilderDelegate((context, index) { | |||||
return Container( | |||||
height: 50, | |||||
width: double.infinity, | |||||
color: Colors.green[(index % 9 + 1) * 100], | |||||
); | |||||
}, childCount: 50)), | |||||
], | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 悬浮按钮 | |||||
Widget _buildFloatWidget() { | |||||
return Visibility( | |||||
visible: true, | |||||
child: GestureDetector( | |||||
onTap: ()=> _scrollTop(), | |||||
behavior: HitTestBehavior.opaque, | |||||
child: Container( | |||||
height: 30, | |||||
width: 30, | |||||
color: Colors.redAccent, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
/// 骨架图 | |||||
Widget _buildSkeletonWidget() { | |||||
return Scaffold(); | |||||
} | |||||
/// 空数据视图 | |||||
Widget _buildEmptyWidget() { | |||||
return Scaffold( | |||||
backgroundColor: HexColor.fromHex('#F9F9F9'), | |||||
appBar: AppBar( | |||||
brightness: Brightness.light, | |||||
backgroundColor: Colors.white, | |||||
leading: IconButton( | |||||
icon: Icon( | |||||
Icons.arrow_back_ios, | |||||
size: 22, | |||||
color: HexColor.fromHex('#333333'), | |||||
), | |||||
onPressed: () => Navigator.maybePop(context), | |||||
), | |||||
title: Text( | |||||
'爆款', | |||||
style: TextStyle(color: HexColor.fromHex('#333333'), fontSize: 15, fontWeight: FontWeight.bold), | |||||
), | |||||
centerTitle: true, | |||||
elevation: 0, | |||||
), | |||||
body: Column( | |||||
crossAxisAlignment: CrossAxisAlignment.center, | |||||
mainAxisAlignment: MainAxisAlignment.center, | |||||
children: <Widget>[ | |||||
Align( | |||||
alignment: Alignment.topCenter, | |||||
child: EmptyWidget( | |||||
tips: '网络似乎开小差了~', | |||||
), | |||||
), | |||||
GestureDetector( | |||||
onTap: () => _onRefreshEvent(), | |||||
behavior: HitTestBehavior.opaque, | |||||
child: Container( | |||||
alignment: Alignment.center, | |||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), border: Border.all(color: HexColor.fromHex('#999999'), width: 0.5), color: Colors.white), | |||||
width: 80, | |||||
height: 20, | |||||
child: Text( | |||||
'刷新一下', | |||||
style: TextStyle(fontSize: 12, color: HexColor.fromHex('#333333'), fontWeight: FontWeight.bold), | |||||
), | |||||
), | |||||
) | |||||
], | |||||
)); | |||||
} | |||||
} | |||||
class _CustomFloatingActionButtonLocation extends FloatingActionButtonLocation { | |||||
FloatingActionButtonLocation location; | |||||
double offsetX; // X方向的偏移量 | |||||
double offsetY; // Y方向的偏移量 | |||||
_CustomFloatingActionButtonLocation(this.location, this.offsetX, this.offsetY); | |||||
@override | |||||
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { | |||||
Offset offset = location.getOffset(scaffoldGeometry); | |||||
return Offset(offset.dx + offsetX, offset.dy + offsetY); | |||||
} | |||||
} |
@@ -0,0 +1,8 @@ | |||||
import 'package:flutter/material.dart'; | |||||
class CommonPageSkeleton extends StatelessWidget { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container(); | |||||
} | |||||
} |
@@ -268,6 +268,7 @@ class _FavoritesPageContainerState extends State<_FavoritesPageContainer> with T | |||||
/// 骨架图 | /// 骨架图 | ||||
Widget _buildSkeletonWidget() { | Widget _buildSkeletonWidget() { | ||||
return Scaffold( | return Scaffold( | ||||
backgroundColor: Colors.white, | |||||
body: Container(), | body: Container(), | ||||
); | ); | ||||
} | } | ||||
@@ -0,0 +1,36 @@ | |||||
import 'dart:async'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_repository.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'feedback_event.dart'; | |||||
import 'feedback_state.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
class FeedbackBloc extends Bloc<FeedbackEvent, FeedbackState> { | |||||
// FeedbackBloc() : super(FeedbackInitial()); | |||||
@override | |||||
FeedbackState get initialState => FeedbackInitial(); | |||||
FeedBackRepository repository; | |||||
FeedbackBloc(this.repository); | |||||
@override | |||||
Stream<FeedbackState> mapEventToState( | |||||
FeedbackEvent event, | |||||
) async* { | |||||
/// 初始化 | |||||
if (event is FeedbackInitEvent) { | |||||
yield* _mapInitToState(event); | |||||
} | |||||
} | |||||
/// 初始化 | |||||
Stream<FeedbackState> _mapInitToState(FeedbackInitEvent event) async* { | |||||
var result = await repository.fetchData(event.model); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
yield FeedbackLoadedState(model: result); | |||||
} else { | |||||
yield FeedbackErrorState(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
import 'package:meta/meta.dart'; | |||||
@immutable | |||||
abstract class FeedbackEvent {} | |||||
/// 初始化 | |||||
class FeedbackInitEvent extends FeedbackEvent{ | |||||
final Map<String, dynamic> model; | |||||
FeedbackInitEvent({this.model}); | |||||
} | |||||
/// 提交反馈 | |||||
class FeedbackSubmitEvent extends FeedbackEvent{} |
@@ -0,0 +1,30 @@ | |||||
import 'dart:convert'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
class FeedBackRepository { | |||||
/// 获取缓存样式数据 | |||||
/// 获取网络样式数据 | |||||
Future<FeedbackModel> fetchData(final Map<String, dynamic> data) async { | |||||
try { | |||||
String skip_identifier = !EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback'; | |||||
var result = await NetUtil.post('/api/v1/mod/$skip_identifier', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||||
var modListData = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list'][0]['data']; | |||||
if (!EmptyUtil.isEmpty(modListData)) { | |||||
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | |||||
return model; | |||||
} | |||||
} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | |||||
} | |||||
/// 获取网络数据 | |||||
} |
@@ -0,0 +1,15 @@ | |||||
import 'package:meta/meta.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | |||||
@immutable | |||||
abstract class FeedbackState {} | |||||
class FeedbackInitial extends FeedbackState {} | |||||
class FeedbackLoadedState extends FeedbackState{ | |||||
FeedbackModel model; | |||||
FeedbackLoadedState({this.model}); | |||||
} | |||||
class FeedbackErrorState extends FeedbackState{} |
@@ -5,33 +5,137 @@ import 'package:flutter/material.dart'; | |||||
import 'package:fluttertoast/fluttertoast.dart'; | import 'package:fluttertoast/fluttertoast.dart'; | ||||
import 'package:image_picker/image_picker.dart'; | import 'package:image_picker/image_picker.dart'; | ||||
import 'package:permission_handler/permission_handler.dart'; | import 'package:permission_handler/permission_handler.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_bloc.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_repository.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_record_page.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/feedback_record_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_image.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_image.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_tab_widget.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_tab_widget.dart'; | ||||
import 'package:zhiying_base_widget/widgets/others/action_selected_alert/action_selected_alert.dart'; | import 'package:zhiying_base_widget/widgets/others/action_selected_alert/action_selected_alert.dart'; | ||||
import 'package:zhiying_comm/util/log/let_log.dart'; | import 'package:zhiying_comm/util/log/let_log.dart'; | ||||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||||
import 'bloc/feedback_bloc.dart'; | |||||
import 'bloc/feedback_repository.dart'; | |||||
import 'bloc/feedback_state.dart'; | |||||
import 'bloc/feedback_event.dart'; | |||||
import 'package:fluttertoast/fluttertoast.dart'; | |||||
/// | |||||
/// 意见反馈 | |||||
/// | |||||
class FeedbackPage extends StatefulWidget { | class FeedbackPage extends StatefulWidget { | ||||
final Map<String, dynamic> data; | |||||
FeedbackPage(this.data); | |||||
@override | @override | ||||
_FeedbackPageState createState() => _FeedbackPageState(); | _FeedbackPageState createState() => _FeedbackPageState(); | ||||
} | } | ||||
class _FeedbackPageState extends State<FeedbackPage> { | class _FeedbackPageState extends State<FeedbackPage> { | ||||
@override | |||||
Widget build(BuildContext context) { | |||||
return BlocProvider<FeedbackBloc>( | |||||
create: (_) => FeedbackBloc(FeedBackRepository())..add(FeedbackInitEvent()), | |||||
child: _FeedbackPageContainer(), | |||||
); | |||||
} | |||||
} | |||||
class _FeedbackPageContainer extends StatefulWidget { | |||||
@override | |||||
__FeedbackPageContainerState createState() => __FeedbackPageContainerState(); | |||||
} | |||||
class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||||
List<File> _images = List(); | List<File> _images = List(); | ||||
bool _submitable = false; | bool _submitable = false; | ||||
TextEditingController _feedback = TextEditingController(); | |||||
TextEditingController _feedback; | |||||
TextEditingController _title; | |||||
@override | |||||
void initState() { | |||||
_feedback = TextEditingController(); | |||||
_title = TextEditingController(); | |||||
super.initState(); | |||||
} | |||||
@override | @override | ||||
void dispose() { | void dispose() { | ||||
_feedback.dispose(); | |||||
_feedback?.dispose(); | |||||
_title?.dispose(); | |||||
super.dispose(); | super.dispose(); | ||||
} | } | ||||
/// 选择图片 | |||||
void _onAddImage() async { | |||||
if (_images.length >= 4) { | |||||
Fluttertoast.showToast(msg: '最多上传4张图片'); | |||||
return; | |||||
} | |||||
var status = await Permission.photos.status; | |||||
if (status != PermissionStatus.granted) { | |||||
status = await Permission.photos.request(); | |||||
} | |||||
if (status == PermissionStatus.denied) { | |||||
Fluttertoast.showToast(msg: '暂无权限,图片选择失败'); | |||||
return null; | |||||
} | |||||
final picker = ImagePicker(); | |||||
PickedFile file; | |||||
int index = await showModalBottomSheet( | |||||
context: context, | |||||
builder: (context) { | |||||
return ActionSelectedAlert( | |||||
// title: '拍照/选择图片', | |||||
actions: ['拍照', '从相册选择图片'], | |||||
); | |||||
}, | |||||
isScrollControlled: false, | |||||
backgroundColor: Colors.transparent); | |||||
if (index != null) { | |||||
if (index == 0) { | |||||
file = await picker.getImage(source: ImageSource.camera); | |||||
} else { | |||||
file = await picker.getImage(source: ImageSource.gallery); | |||||
} | |||||
if (file == null) return; | |||||
setState(() { | |||||
_images.add(File(file.path)); | |||||
}); | |||||
// File resultFile = await EncodeUtil.compressImage(file, 800); | |||||
} | |||||
} | |||||
@override | @override | ||||
Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
return BlocConsumer<FeedbackBloc, FeedbackState>( | |||||
listener: (context, state) {}, | |||||
buildWhen: (prev, current) { | |||||
return true; | |||||
}, | |||||
builder: (context, state) { | |||||
if (state is FeedbackLoadedState) { | |||||
return _getMainWidget(state?.model); | |||||
} | |||||
return _getEmptyWidget(); | |||||
}, | |||||
); | |||||
} | |||||
/// 有数据 | |||||
Widget _getMainWidget(FeedbackModel model) { | |||||
return Scaffold( | return Scaffold( | ||||
resizeToAvoidBottomInset: false, | resizeToAvoidBottomInset: false, | ||||
appBar: _createNav(), | |||||
appBar: _createNav(model), | |||||
body: GestureDetector( | body: GestureDetector( | ||||
onTap: () { | onTap: () { | ||||
FocusScope.of(context).requestFocus(FocusNode()); | FocusScope.of(context).requestFocus(FocusNode()); | ||||
@@ -45,19 +149,16 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
children: <Widget>[ | children: <Widget>[ | ||||
Container( | Container( | ||||
width: double.infinity, | width: double.infinity, | ||||
margin: EdgeInsets.only( | |||||
top: 10, bottom: 10, left: 12.5, right: 12.5), | |||||
margin: EdgeInsets.only(top: 10, bottom: 10, left: 12.5, right: 12.5), | |||||
padding: EdgeInsets.all(12.5), | padding: EdgeInsets.all(12.5), | ||||
decoration: BoxDecoration( | |||||
color: Colors.white, | |||||
borderRadius: BorderRadius.circular(7.5)), | |||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(7.5)), | |||||
child: Column( | child: Column( | ||||
crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
mainAxisAlignment: MainAxisAlignment.start, | mainAxisAlignment: MainAxisAlignment.start, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
_createTitle(), | |||||
_createUpload(), | |||||
_createSubmit(), | |||||
_createTitle(model), | |||||
_createUpload(model), | |||||
_createSubmit(model), | |||||
], | ], | ||||
), | ), | ||||
) | ) | ||||
@@ -81,29 +182,31 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
height: 30, | height: 30, | ||||
margin: EdgeInsets.all(10), | margin: EdgeInsets.all(10), | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
color: Colors.white, | |||||
borderRadius: BorderRadius.circular(15)), | |||||
color: HexColor.fromHex(model?.feedbackListBtnBgColor ?? '#FFFFFF'), | |||||
borderRadius: BorderRadius.circular(15), | |||||
border: Border.all(color: HexColor.fromHex(model?.feedbackListBtnBorderColor ?? '#D1D1D1'), width: 0.5), | |||||
), | |||||
child: Row( | child: Row( | ||||
mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
Padding( | Padding( | ||||
padding: EdgeInsets.only(right: 6), | padding: EdgeInsets.only(right: 6), | ||||
child: Icon( | |||||
Icons.list, | |||||
size: 12, | |||||
child: CachedNetworkImage( | |||||
imageUrl: model?.feedbackListBtnIcon ?? '', | |||||
width: 16.5, | |||||
), | ), | ||||
), | ), | ||||
Text( | Text( | ||||
'反馈记录', | |||||
style: | |||||
TextStyle(fontSize: 13, color: Color(0xff333333)), | |||||
model?.feedbackListBtnText ?? '反馈记录', | |||||
style: TextStyle(fontSize: 13, color: HexColor.fromHex(model?.feedbackListBtnTextColor ?? '#333333'), fontWeight: FontWeight.bold), | |||||
) | ) | ||||
], | ], | ||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
const SizedBox(height: 25), | |||||
], | ], | ||||
), | ), | ||||
), | ), | ||||
@@ -111,8 +214,17 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
); | ); | ||||
} | } | ||||
// 导航栏 | |||||
Widget _createNav() { | |||||
/// 没数据 | |||||
Widget _getEmptyWidget() { | |||||
return Scaffold( | |||||
resizeToAvoidBottomInset: false, | |||||
appBar: _createNav(null), | |||||
body: Container(), | |||||
); | |||||
} | |||||
/// 导航栏 | |||||
Widget _createNav(FeedbackModel mode) { | |||||
return CupertinoNavigationBar( | return CupertinoNavigationBar( | ||||
border: Border( | border: Border( | ||||
bottom: BorderSide( | bottom: BorderSide( | ||||
@@ -120,7 +232,7 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
style: BorderStyle.none, | style: BorderStyle.none, | ||||
), | ), | ||||
), | ), | ||||
backgroundColor: Colors.white, | |||||
backgroundColor: HexColor.fromHex(mode?.appBarBgColor ?? '#FFFFFF'), | |||||
leading: Navigator.canPop(context) | leading: Navigator.canPop(context) | ||||
? GestureDetector( | ? GestureDetector( | ||||
child: Container( | child: Container( | ||||
@@ -138,41 +250,119 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
) | ) | ||||
: Container(), | : Container(), | ||||
middle: Text( | middle: Text( | ||||
'意见反馈', | |||||
mode?.appBarName ?? '意见反馈', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 15, | fontSize: 15, | ||||
color: Color(0xff333333), | |||||
color: HexColor.fromHex(mode?.appBarNameColor ?? '#333333'), | |||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
Widget _createTitle() { | |||||
Widget _createTitle(FeedbackModel model) { | |||||
return Column( | return Column( | ||||
crossAxisAlignment: CrossAxisAlignment.start, | crossAxisAlignment: CrossAxisAlignment.start, | ||||
mainAxisAlignment: MainAxisAlignment.start, | mainAxisAlignment: MainAxisAlignment.start, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
Text( | Text( | ||||
'反馈描述', | |||||
model?.feedbackTitle ?? '反馈描述', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 14, | fontSize: 14, | ||||
color: Color(0xff333333), | color: Color(0xff333333), | ||||
fontWeight: FontWeight.bold, | fontWeight: FontWeight.bold, | ||||
), | ), | ||||
), | ), | ||||
const SizedBox(height: 2), | |||||
/// 异常选项 | |||||
Padding( | Padding( | ||||
padding: EdgeInsets.only(top: 4, bottom: 4), | padding: EdgeInsets.only(top: 4, bottom: 4), | ||||
child: Row( | |||||
children: List.generate( | |||||
3, | |||||
(index) => Expanded( | |||||
child: Container( | |||||
margin: EdgeInsets.only(left: 2, right: 2), | |||||
height: 28, | |||||
child: FeedbackTabWidget('功能异常')), | |||||
)), | |||||
child: Visibility( | |||||
visible: !EmptyUtil.isEmpty(model?.feedbackTypes), | |||||
child: Row( | |||||
children: model.feedbackTypes | |||||
.map((e) => Expanded( | |||||
child: GestureDetector( | |||||
behavior: HitTestBehavior.opaque, | |||||
onTap: (){ | |||||
setState(() { | |||||
model.feedbackTypes.forEach((element) { | |||||
element.isSelect = false; | |||||
}); | |||||
e.isSelect = true; | |||||
}); | |||||
}, | |||||
child: Container( | |||||
margin: EdgeInsets.only(left: 2, right: 2), | |||||
height: 28, | |||||
child: Container( | |||||
decoration: BoxDecoration( | |||||
borderRadius: BorderRadius.circular(2.5), | |||||
border: Border.all( | |||||
color: HexColor.fromHex(e.isSelect ? model?.feedbackTypeSelectedBorderColor : model?.feedbackTypeNoSelectedBorderColor), | |||||
//e.isSelect ? Colors.redAccent : Color(0xffe7e7e7), | |||||
width: 1, | |||||
), | |||||
), | |||||
child: Stack( | |||||
children: <Widget>[ | |||||
Center( | |||||
child: Text( | |||||
e.name ?? '', | |||||
style: TextStyle( | |||||
fontSize: 12, | |||||
color: HexColor.fromHex(e.isSelect | |||||
? model?.feedbackTypeSelectedTextColor | |||||
: model?.feedbackTypeNoSelectedTextColor) //e.isSelect ? Colors.redAccent : Color(0xff999999), | |||||
), | |||||
), | |||||
), | |||||
Visibility( | |||||
visible: e.isSelect, | |||||
child: Align( | |||||
alignment: Alignment.bottomRight, | |||||
child: CachedNetworkImage( | |||||
imageUrl: model?.feedbackTypeSelectedBorderIcon, | |||||
width: 10, | |||||
), | |||||
), | |||||
) | |||||
], | |||||
), | |||||
)), | |||||
))) | |||||
.toList(), | |||||
), | |||||
), | |||||
), | |||||
// 标题 | |||||
Container( | |||||
height: 32.5, | |||||
margin: EdgeInsets.only(left: 2, right: 2, top: 4, bottom: 4), | |||||
child: CupertinoTextField( | |||||
controller: _title, | |||||
textAlignVertical: TextAlignVertical.center, | |||||
style: TextStyle(fontSize: 12, color: Color(0xff333333)), | |||||
maxLines: 1, | |||||
placeholder: model?.feedbackInputHintText ?? '请输入反馈标题(最多15个字)', | |||||
placeholderStyle: TextStyle( | |||||
fontSize: 12, | |||||
color: HexColor.fromHex(model?.feedbackInputHintTextColor ?? '#999999'), | |||||
), | |||||
decoration: BoxDecoration(color: Color(0xfff9f9f9), borderRadius: BorderRadius.circular(7.5)), | |||||
onChanged: (value) { | |||||
if (value == null || value == '' || EmptyUtil.isEmpty(_feedback?.text?.toString()?.trim())) { | |||||
_submitable = false; | |||||
} else { | |||||
_submitable = true; | |||||
} | |||||
setState(() {}); | |||||
}, | |||||
), | ), | ||||
), | ), | ||||
// 内容 | |||||
Container( | Container( | ||||
height: 118, | height: 118, | ||||
margin: EdgeInsets.only(left: 2, right: 2, top: 4, bottom: 4), | margin: EdgeInsets.only(left: 2, right: 2, top: 4, bottom: 4), | ||||
@@ -181,16 +371,14 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
textAlignVertical: TextAlignVertical.top, | textAlignVertical: TextAlignVertical.top, | ||||
style: TextStyle(fontSize: 12, color: Color(0xff333333)), | style: TextStyle(fontSize: 12, color: Color(0xff333333)), | ||||
maxLines: null, | maxLines: null, | ||||
placeholder: '请输入您的意见(最多100个字)', | |||||
placeholder: model?.feedbackInputContentHintText ?? '请输入您的意见(最多100个字)', | |||||
placeholderStyle: TextStyle( | placeholderStyle: TextStyle( | ||||
fontSize: 12, | fontSize: 12, | ||||
color: Color(0xff999999), | |||||
color: HexColor.fromHex(model?.feedbackInputContentHintTextColor ?? '#999999'), | |||||
), | ), | ||||
decoration: BoxDecoration( | |||||
color: Color(0xfff9f9f9), | |||||
borderRadius: BorderRadius.circular(7.5)), | |||||
decoration: BoxDecoration(color: Color(0xfff9f9f9), borderRadius: BorderRadius.circular(7.5)), | |||||
onChanged: (value) { | onChanged: (value) { | ||||
if (value == null || value == '') { | |||||
if (value == null || value == '' || EmptyUtil.isEmpty(_title?.text?.toString()?.trim())) { | |||||
_submitable = false; | _submitable = false; | ||||
} else { | } else { | ||||
_submitable = true; | _submitable = true; | ||||
@@ -203,7 +391,7 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
); | ); | ||||
} | } | ||||
Widget _createUpload() { | |||||
Widget _createUpload(FeedbackModel model) { | |||||
List<Widget> images = List(); | List<Widget> images = List(); | ||||
_images.forEach((file) { | _images.forEach((file) { | ||||
images.add(Container( | images.add(Container( | ||||
@@ -223,9 +411,7 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
images.add(GestureDetector( | images.add(GestureDetector( | ||||
child: Container( | child: Container( | ||||
margin: EdgeInsets.only(top: 4, bottom: 4), | margin: EdgeInsets.only(top: 4, bottom: 4), | ||||
decoration: BoxDecoration( | |||||
borderRadius: BorderRadius.circular(7.5), | |||||
color: Color(0xfff9f9f9)), | |||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(7.5), color: Color(0xfff9f9f9)), | |||||
height: 80, | height: 80, | ||||
width: 80, | width: 80, | ||||
child: Icon( | child: Icon( | ||||
@@ -245,7 +431,7 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
Padding( | Padding( | ||||
padding: EdgeInsets.only(right: 10, top: 4, bottom: 4), | padding: EdgeInsets.only(right: 10, top: 4, bottom: 4), | ||||
child: Text( | child: Text( | ||||
'上传图片', | |||||
model?.feedbackUploadImageTitle ?? '上传图片', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 14, | fontSize: 14, | ||||
color: Color(0xff333333), | color: Color(0xff333333), | ||||
@@ -254,7 +440,7 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
), | ), | ||||
), | ), | ||||
Text( | Text( | ||||
'最多上传4张,大小不超过1M/张', | |||||
model?.feedbackUploadImageSubtitle ?? '最多上传4张,大小不超过1M/张', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 12, | fontSize: 12, | ||||
color: Color(0xff999999), | color: Color(0xff999999), | ||||
@@ -269,27 +455,29 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
); | ); | ||||
} | } | ||||
Widget _createSubmit() { | |||||
Widget _createSubmit(FeedbackModel model) { | |||||
return GestureDetector( | return GestureDetector( | ||||
onTap: () { | onTap: () { | ||||
if (!_submitable) { | if (!_submitable) { | ||||
return; | return; | ||||
} | } | ||||
Logger.debug('提交:${_feedback.text.toString()}'); | Logger.debug('提交:${_feedback.text.toString()}'); | ||||
Fluttertoast.showToast(msg: '提交成功~'); | |||||
Navigator.pop(context); | |||||
}, | }, | ||||
child: Container( | child: Container( | ||||
margin: EdgeInsets.only(top: 24, bottom: 4), | margin: EdgeInsets.only(top: 24, bottom: 4), | ||||
height: 45, | height: 45, | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
color: _submitable ? Colors.redAccent : Color(0xffffe1e1), | |||||
color: HexColor.fromHex(_submitable ? model?.feedbackTypeSelectedBorderColor ?? '' : model?.feedbackPostBtnBgColor ?? ''), | |||||
borderRadius: BorderRadius.circular(7.5), | borderRadius: BorderRadius.circular(7.5), | ||||
), | ), | ||||
child: Center( | child: Center( | ||||
child: Text( | child: Text( | ||||
'提交意见', | |||||
model?.feedbackPostBtnText ?? '提交意见', | |||||
style: TextStyle( | style: TextStyle( | ||||
fontSize: 14, | fontSize: 14, | ||||
color: Colors.white, | |||||
color: HexColor.fromHex(model?.feedbackPostBtnTextColor ?? '#FFFFFF'), | |||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
@@ -297,47 +485,5 @@ class _FeedbackPageState extends State<FeedbackPage> { | |||||
); | ); | ||||
} | } | ||||
void _onAddImage() async { | |||||
if (_images.length >= 4) { | |||||
Fluttertoast.showToast(msg: '最多上传4张图片'); | |||||
return; | |||||
} | |||||
var status = await Permission.photos.status; | |||||
if (status != PermissionStatus.granted) { | |||||
status = await Permission.photos.request(); | |||||
} | |||||
if (status == PermissionStatus.denied) { | |||||
Fluttertoast.showToast(msg: '暂无权限,图片选择失败'); | |||||
return null; | |||||
} | |||||
final picker = ImagePicker(); | |||||
PickedFile file; | |||||
int index = await showModalBottomSheet( | |||||
context: context, | |||||
builder: (context) { | |||||
return ActionSelectedAlert( | |||||
// title: '拍照/选择图片', | |||||
actions: ['拍照', '从相册选择图片'], | |||||
); | |||||
}, | |||||
isScrollControlled: false, | |||||
backgroundColor: Colors.transparent); | |||||
if (index != null) { | |||||
if (index == 0) { | |||||
file = await picker.getImage(source: ImageSource.camera); | |||||
} else { | |||||
file = await picker.getImage(source: ImageSource.gallery); | |||||
} | |||||
if (file == null) return; | |||||
setState(() { | |||||
_images.add(File(file.path)); | |||||
}); | |||||
// File resultFile = await EncodeUtil.compressImage(file, 800); | |||||
} | |||||
} | |||||
} | } |
@@ -1,6 +1,7 @@ | |||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_record_item.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_record_item.dart'; | ||||
import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; | |||||
class FeedbackRecordPage extends StatefulWidget { | class FeedbackRecordPage extends StatefulWidget { | ||||
@override | @override | ||||
@@ -17,11 +18,12 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||||
FocusScope.of(context).requestFocus(FocusNode()); | FocusScope.of(context).requestFocus(FocusNode()); | ||||
}, | }, | ||||
child: SafeArea( | child: SafeArea( | ||||
child: ListView.builder( | |||||
itemCount: 10, | |||||
itemBuilder: (context, index) { | |||||
return FeedbackRecordItem(); | |||||
}), | |||||
child: Center(child: EmptyWidget()), | |||||
// child: ListView.builder( | |||||
// itemCount: 10, | |||||
// itemBuilder: (context, index) { | |||||
// return FeedbackRecordItem(); | |||||
// }), | |||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
@@ -0,0 +1,194 @@ | |||||
class FeedbackModel { | |||||
String appBarName; | |||||
String appBarNameColor; | |||||
String appBarBgColor; | |||||
String bgColor; | |||||
String feedbackBgColor; | |||||
String feedbackTitle; | |||||
String feedbackTypeNoSelectedBorderColor; | |||||
String feedbackTypeNoSelectedTextColor; | |||||
String feedbackTypeSelectedBorderColor; | |||||
String feedbackTypeSelectedTextColor; | |||||
String feedbackTypeSelectedBorderIcon; | |||||
List<FeedbackTypes> feedbackTypes; | |||||
String feedbackInputBgColor; | |||||
String feedbackInputHintText; | |||||
String feedbackInputHintTextColor; | |||||
String feedbackInputLimitText; | |||||
String feedbackInputLimitTextColor; | |||||
String feedbackInputContentBgColor; | |||||
String feedbackInputContentHintText; | |||||
String feedbackInputContentLimitText; | |||||
String feedbackInputContentHintTextColor; | |||||
String feedbackInputContentLimitTextColor; | |||||
String feedbackUploadImageTitle; | |||||
String feedbackUploadImageSubtitle; | |||||
String feedbackPostBtnText; | |||||
String feedbackPostBtnBgColor; | |||||
String feedbackPostBtnTextColor; | |||||
String feedbackListBtnIcon; | |||||
String feedbackListBtnText; | |||||
String feedbackListBtnTextColor; | |||||
String feedbackListBtnBgColor; | |||||
String feedbackListBtnBorderColor; | |||||
String requiredLogin; | |||||
String requiredTaobaoAuth; | |||||
String skipIdentifier; | |||||
FeedbackModel( | |||||
{this.appBarName, | |||||
this.appBarNameColor, | |||||
this.appBarBgColor, | |||||
this.bgColor, | |||||
this.feedbackBgColor, | |||||
this.feedbackTitle, | |||||
this.feedbackTypeNoSelectedBorderColor, | |||||
this.feedbackTypeNoSelectedTextColor, | |||||
this.feedbackTypeSelectedBorderColor, | |||||
this.feedbackTypeSelectedTextColor, | |||||
this.feedbackTypeSelectedBorderIcon, | |||||
this.feedbackTypes, | |||||
this.feedbackInputBgColor, | |||||
this.feedbackInputHintText, | |||||
this.feedbackInputHintTextColor, | |||||
this.feedbackInputLimitText, | |||||
this.feedbackInputLimitTextColor, | |||||
this.feedbackInputContentBgColor, | |||||
this.feedbackInputContentHintText, | |||||
this.feedbackInputContentLimitText, | |||||
this.feedbackInputContentHintTextColor, | |||||
this.feedbackInputContentLimitTextColor, | |||||
this.feedbackUploadImageTitle, | |||||
this.feedbackUploadImageSubtitle, | |||||
this.feedbackPostBtnText, | |||||
this.feedbackPostBtnBgColor, | |||||
this.feedbackPostBtnTextColor, | |||||
this.feedbackListBtnIcon, | |||||
this.feedbackListBtnText, | |||||
this.feedbackListBtnTextColor, | |||||
this.feedbackListBtnBgColor, | |||||
this.feedbackListBtnBorderColor, | |||||
this.requiredLogin, | |||||
this.requiredTaobaoAuth, | |||||
this.skipIdentifier}); | |||||
FeedbackModel.fromJson(Map<String, dynamic> json) { | |||||
appBarName = json['app_bar_name']; | |||||
appBarNameColor = json['app_bar_name_color']; | |||||
appBarBgColor = json['app_bar_bg_color']; | |||||
bgColor = json['bg_color']; | |||||
feedbackBgColor = json['feedback_bg_color']; | |||||
feedbackTitle = json['feedback_title']; | |||||
feedbackTypeNoSelectedBorderColor = | |||||
json['feedback_type_no_selected_border_color']; | |||||
feedbackTypeNoSelectedTextColor = | |||||
json['feedback_type_no_selected_text_color']; | |||||
feedbackTypeSelectedBorderColor = | |||||
json['feedback_type_selected_border_color']; | |||||
feedbackTypeSelectedTextColor = json['feedback_type_selected_text_color']; | |||||
feedbackTypeSelectedBorderIcon = json['feedback_type_selected_border_icon']; | |||||
if (json['feedback_types'] != null) { | |||||
feedbackTypes = new List<FeedbackTypes>(); | |||||
json['feedback_types'].forEach((v) { | |||||
feedbackTypes.add(new FeedbackTypes.fromJson(v)); | |||||
}); | |||||
} | |||||
feedbackInputBgColor = json['feedback_input_bg_color']; | |||||
feedbackInputHintText = json['feedback_input_hint_text']; | |||||
feedbackInputHintTextColor = json['feedback_input_hint_text_color']; | |||||
feedbackInputLimitText = json['feedback_input_limit_text']; | |||||
feedbackInputLimitTextColor = json['feedback_input_limit_text_color']; | |||||
feedbackInputContentBgColor = json['feedback_input_content_bg_color']; | |||||
feedbackInputContentHintText = json['feedback_input_content_hint_text']; | |||||
feedbackInputContentLimitText = json['feedback_input_content_limit_text']; | |||||
feedbackInputContentHintTextColor = | |||||
json['feedback_input_content_hint_text_color']; | |||||
feedbackInputContentLimitTextColor = | |||||
json['feedback_input_content_limit_text_color']; | |||||
feedbackUploadImageTitle = json['feedback_upload_image_title']; | |||||
feedbackUploadImageSubtitle = json['feedback_upload_image_subtitle']; | |||||
feedbackPostBtnText = json['feedback_post_btn_text']; | |||||
feedbackPostBtnBgColor = json['feedback_post_btn_bg_color']; | |||||
feedbackPostBtnTextColor = json['feedback_post_btn_text_color']; | |||||
feedbackListBtnIcon = json['feedback_list_btn_icon']; | |||||
feedbackListBtnText = json['feedback_list_btn_text']; | |||||
feedbackListBtnTextColor = json['feedback_list_btn_text_color']; | |||||
feedbackListBtnBgColor = json['feedback_list_btn_bg_color']; | |||||
feedbackListBtnBorderColor = json['feedback_list_btn_border_color']; | |||||
requiredLogin = json['required_login']; | |||||
requiredTaobaoAuth = json['required_taobao_auth']; | |||||
skipIdentifier = json['skip_identifier']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['app_bar_name'] = this.appBarName; | |||||
data['app_bar_name_color'] = this.appBarNameColor; | |||||
data['app_bar_bg_color'] = this.appBarBgColor; | |||||
data['bg_color'] = this.bgColor; | |||||
data['feedback_bg_color'] = this.feedbackBgColor; | |||||
data['feedback_title'] = this.feedbackTitle; | |||||
data['feedback_type_no_selected_border_color'] = | |||||
this.feedbackTypeNoSelectedBorderColor; | |||||
data['feedback_type_no_selected_text_color'] = | |||||
this.feedbackTypeNoSelectedTextColor; | |||||
data['feedback_type_selected_border_color'] = | |||||
this.feedbackTypeSelectedBorderColor; | |||||
data['feedback_type_selected_text_color'] = | |||||
this.feedbackTypeSelectedTextColor; | |||||
data['feedback_type_selected_border_icon'] = | |||||
this.feedbackTypeSelectedBorderIcon; | |||||
if (this.feedbackTypes != null) { | |||||
data['feedback_types'] = | |||||
this.feedbackTypes.map((v) => v.toJson()).toList(); | |||||
} | |||||
data['feedback_input_bg_color'] = this.feedbackInputBgColor; | |||||
data['feedback_input_hint_text'] = this.feedbackInputHintText; | |||||
data['feedback_input_hint_text_color'] = this.feedbackInputHintTextColor; | |||||
data['feedback_input_limit_text'] = this.feedbackInputLimitText; | |||||
data['feedback_input_limit_text_color'] = this.feedbackInputLimitTextColor; | |||||
data['feedback_input_content_bg_color'] = this.feedbackInputContentBgColor; | |||||
data['feedback_input_content_hint_text'] = | |||||
this.feedbackInputContentHintText; | |||||
data['feedback_input_content_limit_text'] = | |||||
this.feedbackInputContentLimitText; | |||||
data['feedback_input_content_hint_text_color'] = | |||||
this.feedbackInputContentHintTextColor; | |||||
data['feedback_input_content_limit_text_color'] = | |||||
this.feedbackInputContentLimitTextColor; | |||||
data['feedback_upload_image_title'] = this.feedbackUploadImageTitle; | |||||
data['feedback_upload_image_subtitle'] = this.feedbackUploadImageSubtitle; | |||||
data['feedback_post_btn_text'] = this.feedbackPostBtnText; | |||||
data['feedback_post_btn_bg_color'] = this.feedbackPostBtnBgColor; | |||||
data['feedback_post_btn_text_color'] = this.feedbackPostBtnTextColor; | |||||
data['feedback_list_btn_icon'] = this.feedbackListBtnIcon; | |||||
data['feedback_list_btn_text'] = this.feedbackListBtnText; | |||||
data['feedback_list_btn_text_color'] = this.feedbackListBtnTextColor; | |||||
data['feedback_list_btn_bg_color'] = this.feedbackListBtnBgColor; | |||||
data['feedback_list_btn_border_color'] = this.feedbackListBtnBorderColor; | |||||
data['required_login'] = this.requiredLogin; | |||||
data['required_taobao_auth'] = this.requiredTaobaoAuth; | |||||
data['skip_identifier'] = this.skipIdentifier; | |||||
return data; | |||||
} | |||||
} | |||||
class FeedbackTypes { | |||||
String typeId; | |||||
String name; | |||||
bool isSelect = false; | |||||
FeedbackTypes({this.typeId, this.name}); | |||||
FeedbackTypes.fromJson(Map<String, dynamic> json) { | |||||
typeId = json['type_id']; | |||||
name = json['name']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['type_id'] = this.typeId; | |||||
data['name'] = this.name; | |||||
return data; | |||||
} | |||||
} |
@@ -13,7 +13,8 @@ class GoodsDetailsPageRepository { | |||||
String goodId = model['good_id']?.toString(); | String goodId = model['good_id']?.toString(); | ||||
if (!EmptyUtil.isEmpty(provider) && !EmptyUtil.isEmpty(goodId)) { | if (!EmptyUtil.isEmpty(provider) && !EmptyUtil.isEmpty(goodId)) { | ||||
Map<String, dynamic> detailData = model['detail_data']; | Map<String, dynamic> detailData = model['detail_data']; | ||||
return _baseDataProcess(true, goodId, provider, detailData); | |||||
String good_image = model['good_image']; | |||||
return _baseDataProcess(true, goodId, provider, detailData, good_image); | |||||
} | } | ||||
} | } | ||||
} catch (e, s) { | } catch (e, s) { | ||||
@@ -22,7 +23,7 @@ class GoodsDetailsPageRepository { | |||||
return null; | return null; | ||||
} | } | ||||
/// 获取数据 | |||||
/// 获取网络数据 | |||||
Future<List<Map<String, dynamic>>> fetchInitModData(final Map<String, dynamic> model) async { | Future<List<Map<String, dynamic>>> fetchInitModData(final Map<String, dynamic> model) async { | ||||
try { | try { | ||||
String provider = model['provider']; | String provider = model['provider']; | ||||
@@ -31,7 +32,7 @@ class GoodsDetailsPageRepository { | |||||
Logger.log('商品类型 = $provider, 商品ID = $goodId'); | Logger.log('商品类型 = $provider, 商品ID = $goodId'); | ||||
var result = await NetUtil.post('/api/v1/detail/$provider/$goodId', method: NetMethod.GET); | var result = await NetUtil.post('/api/v1/detail/$provider/$goodId', method: NetMethod.GET); | ||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | ||||
return _baseDataProcess(false, goodId, provider, result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||||
return _baseDataProcess(false, goodId, provider, result[GlobalConfig.HTTP_RESPONSE_KEY_DATA], null); | |||||
} | } | ||||
} | } | ||||
} catch (e, s) { | } catch (e, s) { | ||||
@@ -41,7 +42,7 @@ class GoodsDetailsPageRepository { | |||||
} | } | ||||
/// 数据处理 | /// 数据处理 | ||||
List<Map<String, dynamic>> _baseDataProcess(bool parentInput,String goodId, String provider, final Map<String, dynamic> model) { | |||||
List<Map<String, dynamic>> _baseDataProcess(bool parentInput,String goodId, String provider, final Map<String, dynamic> model, String coverImage) { | |||||
if (!EmptyUtil.isEmpty(provider) && !EmptyUtil.isEmpty(goodId) && !EmptyUtil.isEmpty(model)) { | if (!EmptyUtil.isEmpty(provider) && !EmptyUtil.isEmpty(goodId) && !EmptyUtil.isEmpty(model)) { | ||||
try { | try { | ||||
List<Map<String, dynamic>> _pageData = []; | List<Map<String, dynamic>> _pageData = []; | ||||
@@ -59,6 +60,9 @@ class GoodsDetailsPageRepository { | |||||
var imageList = data['image_list']; | var imageList = data['image_list']; | ||||
if (!EmptyUtil.isEmpty(imageList)) { | if (!EmptyUtil.isEmpty(imageList)) { | ||||
_parentGoodsCoverImg = imageList[0]; | _parentGoodsCoverImg = imageList[0]; | ||||
}else if (!EmptyUtil.isEmpty(coverImage)){ | |||||
_parentGoodsCoverImg = coverImage; | |||||
data['image_list'] = [coverImage]; | |||||
} | } | ||||
} catch (e, s) { | } catch (e, s) { | ||||
Logger.error(e, s); | Logger.error(e, s); | ||||
@@ -69,6 +73,8 @@ class GoodsDetailsPageRepository { | |||||
if(data['image_list'][0] != _parentGoodsCoverImg) { | if(data['image_list'][0] != _parentGoodsCoverImg) { | ||||
data['image_list'].insert(0, _parentGoodsCoverImg); | data['image_list'].insert(0, _parentGoodsCoverImg); | ||||
} | } | ||||
}else if(!EmptyUtil.isEmpty(_parentGoodsCoverImg) && !EmptyUtil.isEmpty(data) && EmptyUtil.isEmpty(data['image_list'])){ | |||||
data['image_list'] = [_parentGoodsCoverImg]; | |||||
} | } | ||||
}catch(e, s){ | }catch(e, s){ | ||||
Logger.error(e, s); | Logger.error(e, s); | ||||
@@ -28,11 +28,6 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> { | |||||
if (event is SearchInitEvent) { | if (event is SearchInitEvent) { | ||||
yield* _mapInitEventToState(event); | yield* _mapInitEventToState(event); | ||||
} | } | ||||
/// 搜索的方法 | |||||
if (event is SearchSubmitEvent) { | |||||
yield* _mapSearchSubmitToState(event); | |||||
} | |||||
} | } | ||||
/// 初始化 | /// 初始化 | ||||
@@ -53,8 +48,5 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> { | |||||
} | } | ||||
} | } | ||||
/// 搜索的方法 | |||||
Stream<SearchState> _mapSearchSubmitToState(SearchSubmitEvent event) async* { | |||||
var result = await repository.fetchSearchSubmit(event.model); | |||||
} | |||||
} | } |
@@ -4,32 +4,39 @@ class SearchRepository { | |||||
List<Map<String, dynamic>> _pageData = []; | List<Map<String, dynamic>> _pageData = []; | ||||
/// 获取网络数据 | /// 获取网络数据 | ||||
Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> model) async { | |||||
var result = await NetUtil.post('/api/v1/mod/pub.flutter.search_index', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | |||||
try { | |||||
Future<List<Map<String, dynamic>>> fetchInit(final Map<String, dynamic> data) async { | |||||
try { | |||||
String skipIdentifier = !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) | |||||
? data[GlobalConfig.SKIP_IDENTIFIER] | |||||
: 'pub.flutter.search_index'; | |||||
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); | |||||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result)) { | |||||
_pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | _pageData = List.from(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list']); | ||||
return _pageData; | return _pageData; | ||||
} catch (e) { | |||||
Logger.error(e.toString()); | |||||
} | } | ||||
} catch (e, s) { | |||||
Logger.error(e.toString(), s); | |||||
} | } | ||||
return null; | return null; | ||||
} | } | ||||
/// 获取缓存数据 | /// 获取缓存数据 | ||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> model) async{ | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/pub.flutter.search_index'); | |||||
Future<List<Map<String, dynamic>>> fetchCachedData(final Map<String, dynamic> data) async { | |||||
try { | try { | ||||
String skipIdentifier = !EmptyUtil.isEmpty(data) && data.containsKey(GlobalConfig.SKIP_IDENTIFIER) && !EmptyUtil.isEmpty(data[GlobalConfig.SKIP_IDENTIFIER]) | |||||
? data[GlobalConfig.SKIP_IDENTIFIER] | |||||
: 'pub.flutter.search_index'; | |||||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); | |||||
if (!EmptyUtil.isEmpty(result)) { | if (!EmptyUtil.isEmpty(result)) { | ||||
return List.from(result['mod_list']); | return List.from(result['mod_list']); | ||||
} | } | ||||
}catch(e){} | |||||
} catch (e, s) { | |||||
Logger.error(e, s); | |||||
} | |||||
return null; | return null; | ||||
} | } | ||||
/// 搜索的方法 | |||||
Future<void> fetchSearchSubmit(final String model) async { | |||||
var result = await NetUtil.post(''); | |||||
} | |||||
} | } |
@@ -1,4 +1,5 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:flutter/services.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_repository.dart'; | import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_repository.dart'; | ||||
@@ -115,12 +116,15 @@ class _SearchPageContianerState extends State<SearchPageContianer> { | |||||
/// 主视图 | /// 主视图 | ||||
Widget _getMainWidget(List<Map<String, dynamic>> datas) { | Widget _getMainWidget(List<Map<String, dynamic>> datas) { | ||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Listener( | |||||
onPointerDown: (down) => RouterUtil.hideKeyboard(context), | |||||
child: Column( | |||||
children: _createContentWidget(datas), | |||||
return AnnotatedRegion<SystemUiOverlayStyle>( | |||||
value: SystemUiOverlayStyle.dark, | |||||
child: Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Listener( | |||||
onPointerDown: (down) => RouterUtil.hideKeyboard(context), | |||||
child: Column( | |||||
children: _createContentWidget(datas), | |||||
), | |||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
@@ -1,4 +1,5 @@ | |||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:flutter/services.dart'; | |||||
import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | import 'package:zhiying_base_widget/pages/search_page/notifier/search_tag_notifier.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_result_page/bloc/search_result_bloc.dart'; | import 'package:zhiying_base_widget/pages/search_result_page/bloc/search_result_bloc.dart'; | ||||
import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | import 'package:zhiying_base_widget/pages/search_think_page/bloc/search_think_bloc.dart'; | ||||
@@ -82,12 +83,15 @@ class _SearchResultContianerState extends State<SearchResultContianer> { | |||||
/// 获取主视图 | /// 获取主视图 | ||||
Widget _getMainWidget(List<Map<String, dynamic>> data) { | Widget _getMainWidget(List<Map<String, dynamic>> data) { | ||||
return Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Column( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
children: _createContentWidget(data), | |||||
return AnnotatedRegion<SystemUiOverlayStyle>( | |||||
value: SystemUiOverlayStyle.dark, | |||||
child: Scaffold( | |||||
backgroundColor: Colors.white, | |||||
body: Column( | |||||
crossAxisAlignment: CrossAxisAlignment.start, | |||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
children: _createContentWidget(data), | |||||
), | |||||
), | ), | ||||
); | ); | ||||
} | } | ||||
@@ -185,9 +185,10 @@ class _SettingContainerState extends State<_SettingContainer> { | |||||
), | ), | ||||
), | ), | ||||
), | ), | ||||
onTap: () { | |||||
onTap: () async{ | |||||
Logger.debug('退出登录'); | Logger.debug('退出登录'); | ||||
Provider.of<UserInfoNotifier>(context, listen: false).unLogin(); | |||||
await Provider.of<UserInfoNotifier>(context, listen: false).unLogin(); | |||||
Navigator.maybePop(context); | |||||
}, | }, | ||||
); | ); | ||||
} | } | ||||
@@ -1,7 +1,9 @@ | |||||
import 'package:flutter/cupertino.dart'; | |||||
import 'package:sharesdk_plugin/sharesdk_interface.dart'; | import 'package:sharesdk_plugin/sharesdk_interface.dart'; | ||||
import 'package:sharesdk_plugin/sharesdk_register.dart'; | import 'package:sharesdk_plugin/sharesdk_register.dart'; | ||||
import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/about_us_page/about_us_page.dart'; | import 'package:zhiying_base_widget/pages/about_us_page/about_us_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/custom_page/custom_page.dart'; | |||||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_page.dart'; | import 'package:zhiying_base_widget/pages/feedback_page/feedback_page.dart'; | ||||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | ||||
@@ -99,7 +101,7 @@ class BaseWidgetRegister { | |||||
}); | }); | ||||
Application.addMethod(() async { | Application.addMethod(() async { | ||||
return Future.delayed(Duration(seconds: 2)); | |||||
return Future.delayed(Duration(seconds: 1)); | |||||
}); | }); | ||||
} | } | ||||
@@ -112,11 +114,11 @@ class BaseWidgetRegister { | |||||
PageFactory.regist('pub.flutter.hot_rank', (model) => HotRankingPage(model)); | PageFactory.regist('pub.flutter.hot_rank', (model) => HotRankingPage(model)); | ||||
PageFactory.regist('pub.flutter.my_wallet', (model) => WalletPage(data: model)); | PageFactory.regist('pub.flutter.my_wallet', (model) => WalletPage(data: model)); | ||||
PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); | PageFactory.regist('goods_details', (model) => GoodsDetailsPage(model)); | ||||
PageFactory.regist('search', (model) => SearchPage(model)); | |||||
PageFactory.regist('pub.flutter.search_index', (model) => SearchPage(model)); | |||||
PageFactory.regist('search_item_page', (model) => SearchItemPage(model)); | PageFactory.regist('search_item_page', (model) => SearchItemPage(model)); | ||||
PageFactory.regist('pub.flutter.search_index', (model) => SearchResultPage(model)); | PageFactory.regist('pub.flutter.search_index', (model) => SearchResultPage(model)); | ||||
PageFactory.regist('search_result_item', (model) => SearchResultItemPage(model)); | PageFactory.regist('search_result_item', (model) => SearchResultItemPage(model)); | ||||
PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage()); | |||||
PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage(model)); | |||||
PageFactory.regist('pub.flutter.wechat_teacher', (model) => WechatTeacherPage()); | PageFactory.regist('pub.flutter.wechat_teacher', (model) => WechatTeacherPage()); | ||||
PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model)); | PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model)); | ||||
@@ -159,6 +161,8 @@ class BaseWidgetRegister { | |||||
PageFactory.regist('pub.flutter.message_settings', (model) => MessageSettingsPage(model)); | PageFactory.regist('pub.flutter.message_settings', (model) => MessageSettingsPage(model)); | ||||
/// 钱包明细 | /// 钱包明细 | ||||
PageFactory.regist('pub.flutter.my_wallet_detail', (model) => BilDetailPage(model)); | PageFactory.regist('pub.flutter.my_wallet_detail', (model) => BilDetailPage(model)); | ||||
/// 通用模块 | |||||
PageFactory.regist('pub.flutter.custom', (model) => CustomPage(model)); | |||||
} | } | ||||
// 注册控件 | // 注册控件 | ||||
@@ -0,0 +1,16 @@ | |||||
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,0 +1,45 @@ | |||||
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, | |||||
), | |||||
), | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
/// | |||||
/// 通用模块的搜索栏 | |||||
/// | |||||
class CustomSearchWidget extends StatelessWidget { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container(); | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
import 'package:flutter/material.dart'; | |||||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
/// | |||||
/// 通用模块的tabbar | |||||
/// | |||||
class CustomTabBarWidget extends StatelessWidget { | |||||
@override | |||||
Widget build(BuildContext context) { | |||||
return Container(); | |||||
} | |||||
} |
@@ -9,9 +9,7 @@ import 'package:zhiying_comm/zhiying_comm.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
import 'package:cached_network_image/cached_network_image.dart'; | import 'package:cached_network_image/cached_network_image.dart'; | ||||
import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||
import 'package:flutter_alibc/alibc_model.dart'; | |||||
import 'package:flutter_alibc/flutter_alibc.dart'; | |||||
import 'package:fluttertoast/fluttertoast.dart'; | |||||
import 'package:zhiying_comm/util/turn_chain/turn_chain_util.dart'; | |||||
/// | /// | ||||
/// 优惠券widget | /// 优惠券widget | ||||
@@ -60,33 +58,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||||
/// 点击领取 | /// 点击领取 | ||||
void _onJump(CounponModel model) async{ | void _onJump(CounponModel model) async{ | ||||
print(_user?.toString()); | |||||
if (_user?.token == null || _user.token == '') { | |||||
print('need login...'); | |||||
RouterUtil.goLogin(context); | |||||
return; | |||||
} | |||||
if (EmptyUtil.isEmpty(model.buy_url)) { | |||||
Fluttertoast.showToast(msg: '购买链接不存在'); | |||||
return; | |||||
} | |||||
if (model.provider== 'taobao') { | |||||
// bool isAuth = await TaobaoAuth.isAuth(); | |||||
if (!_user.isTBAuth) { | |||||
TaobaoAuth.auth(context); | |||||
return; | |||||
} | |||||
TradeResult result; | |||||
if (Platform.isAndroid) { | |||||
result = await FlutterAlibc.openByUrl(url: model.buy_url, backUrl: "alisdk://"); | |||||
} else if (Platform.isIOS) { | |||||
result = await FlutterAlibc.openByUrl(url: model.buy_url); | |||||
} | |||||
Logger.debug('${result.errorCode} ${result.errorMessage} '); | |||||
} else { | |||||
RouterUtil.openWebview(model.buy_url, context); | |||||
} | |||||
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model.toJson()); | |||||
} | } | ||||
@override | @override | ||||
@@ -12,6 +12,7 @@ class CounponModel { | |||||
String buy_url; | String buy_url; | ||||
String provider; | String provider; | ||||
String goood_id; | String goood_id; | ||||
ConvertArgs convertArgs; | |||||
CounponModel({ | CounponModel({ | ||||
this.goood_id, | this.goood_id, | ||||
@@ -27,6 +28,7 @@ class CounponModel { | |||||
this.price_type, | this.price_type, | ||||
this.price_type_color, | this.price_type_color, | ||||
this.buy_url, | this.buy_url, | ||||
this.convertArgs, | |||||
}); | }); | ||||
factory CounponModel.fromJson(Map<String, dynamic> json) { | factory CounponModel.fromJson(Map<String, dynamic> json) { | ||||
@@ -44,6 +46,8 @@ class CounponModel { | |||||
price_type: json['price_type'], | price_type: json['price_type'], | ||||
price_type_color: json['price_type_color'], | price_type_color: json['price_type_color'], | ||||
buy_url: json['buy_url'], | buy_url: json['buy_url'], | ||||
convertArgs: json['convert_args'] != null ? ConvertArgs.fromJson(json['convert_args']) : null, | |||||
); | ); | ||||
} | } | ||||
@@ -62,6 +66,42 @@ class CounponModel { | |||||
data['buy_url'] = this.buy_url; | data['buy_url'] = this.buy_url; | ||||
data['provider'] = this.provider; | data['provider'] = this.provider; | ||||
data['goood_id'] = this.goood_id; | data['goood_id'] = this.goood_id; | ||||
if (this.convertArgs != null) { | |||||
data['convert_args'] = this.convertArgs.toJson(); | |||||
} | |||||
return data; | return data; | ||||
} | } | ||||
} | } | ||||
class ConvertArgs { | |||||
String gid; | |||||
String goodUrl; | |||||
String couponUrl; | |||||
String couponPrice; | |||||
String activityUrl; | |||||
String isShare; | |||||
ConvertArgs({this.gid, this.goodUrl, this.couponUrl, this.couponPrice, this.activityUrl, this.isShare}); | |||||
ConvertArgs.fromJson(Map<String, dynamic> json) { | |||||
gid = json['gid']; | |||||
goodUrl = json['good_url']; | |||||
couponUrl = json['coupon_url']; | |||||
couponPrice = json['coupon_price']; | |||||
activityUrl = json['activity_url']; | |||||
isShare = json['is_share']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['gid'] = this.gid; | |||||
data['good_url'] = this.goodUrl; | |||||
data['coupon_url'] = this.couponUrl; | |||||
data['coupon_price'] = this.couponPrice; | |||||
data['activity_url'] = this.activityUrl; | |||||
data['is_share'] = this.isShare; | |||||
return data; | |||||
} | |||||
} | |||||
@@ -1,11 +1,8 @@ | |||||
import 'dart:convert'; | import 'dart:convert'; | ||||
import 'dart:io'; | |||||
import 'package:cached_network_image/cached_network_image.dart'; | import 'package:cached_network_image/cached_network_image.dart'; | ||||
import 'package:flutter/cupertino.dart'; | import 'package:flutter/cupertino.dart'; | ||||
import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||
import 'package:flutter_alibc/alibc_model.dart'; | |||||
import 'package:flutter_alibc/flutter_alibc.dart'; | |||||
import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||
import 'package:fluttertoast/fluttertoast.dart'; | import 'package:fluttertoast/fluttertoast.dart'; | ||||
import 'package:provider/provider.dart'; | import 'package:provider/provider.dart'; | ||||
@@ -15,6 +12,7 @@ import 'package:zhiying_base_widget/widgets/goods_details/footer/bloc/goods_deta | |||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_sk.dart'; | import 'package:zhiying_base_widget/widgets/goods_details/footer/goods_details_footer_sk.dart'; | ||||
import 'package:zhiying_base_widget/widgets/goods_details/footer/model/goods_details_footer_model.dart'; | import 'package:zhiying_base_widget/widgets/goods_details/footer/model/goods_details_footer_model.dart'; | ||||
import 'package:zhiying_comm/zhiying_comm.dart'; | import 'package:zhiying_comm/zhiying_comm.dart'; | ||||
import 'package:zhiying_comm/util/turn_chain/turn_chain_util.dart'; | |||||
/// | /// | ||||
/// 商品详情底部Widget | /// 商品详情底部Widget | ||||
@@ -30,8 +28,7 @@ class GoodsDetailsFooterWidget extends StatelessWidget { | |||||
visible: !EmptyUtil.isEmpty(model), | visible: !EmptyUtil.isEmpty(model), | ||||
replacement: GoodsDetailsFooterSkeleton(), | replacement: GoodsDetailsFooterSkeleton(), | ||||
child: BlocProvider<GoodsDetailsFooterBloc>( | child: BlocProvider<GoodsDetailsFooterBloc>( | ||||
create: (_) => | |||||
GoodsDetailsFooterBloc(repository: GoodsDetailsFooterRepository()), | |||||
create: (_) => GoodsDetailsFooterBloc(repository: GoodsDetailsFooterRepository()), | |||||
//..add(GoodsDetailsFooterInitEvent(model: model)), | //..add(GoodsDetailsFooterInitEvent(model: model)), | ||||
child: GooddsDetailsFooterContainer( | child: GooddsDetailsFooterContainer( | ||||
model, | model, | ||||
@@ -48,18 +45,15 @@ class GooddsDetailsFooterContainer extends StatefulWidget { | |||||
const GooddsDetailsFooterContainer(this.model, {Key key}) : super(key: key); | const GooddsDetailsFooterContainer(this.model, {Key key}) : super(key: key); | ||||
@override | @override | ||||
_GooddsDetailsFooterContainerState createState() => | |||||
_GooddsDetailsFooterContainerState(); | |||||
_GooddsDetailsFooterContainerState createState() => _GooddsDetailsFooterContainerState(); | |||||
} | } | ||||
class _GooddsDetailsFooterContainerState | |||||
extends State<GooddsDetailsFooterContainer> { | |||||
class _GooddsDetailsFooterContainerState extends State<GooddsDetailsFooterContainer> { | |||||
UserInfoModel _user; | UserInfoModel _user; | ||||
@override | @override | ||||
void initState() { | void initState() { | ||||
BlocProvider.of<GoodsDetailsFooterBloc>(context) | |||||
.add(GoodsDetailsFooterInitEvent(model: widget?.model)); | |||||
BlocProvider.of<GoodsDetailsFooterBloc>(context).add(GoodsDetailsFooterInitEvent(model: widget?.model)); | |||||
super.initState(); | super.initState(); | ||||
} | } | ||||
@@ -73,9 +67,7 @@ class _GooddsDetailsFooterContainerState | |||||
void _openHome() { | void _openHome() { | ||||
Navigator.pushAndRemoveUntil( | Navigator.pushAndRemoveUntil( | ||||
context, | context, | ||||
CupertinoPageRoute( | |||||
builder: (BuildContext context) => | |||||
PageFactory.create('homePage', null)), | |||||
CupertinoPageRoute(builder: (BuildContext context) => PageFactory.create('homePage', null)), | |||||
(Route<dynamic> route) => false, | (Route<dynamic> route) => false, | ||||
); | ); | ||||
} | } | ||||
@@ -83,84 +75,57 @@ class _GooddsDetailsFooterContainerState | |||||
/// 收藏 | /// 收藏 | ||||
void _collectOnClick(GoodsDetailsFooterModel model) { | void _collectOnClick(GoodsDetailsFooterModel model) { | ||||
bool isCollect = model.isFav == '0'; | bool isCollect = model.isFav == '0'; | ||||
if(isCollect){ // 收藏 | |||||
if (isCollect) { | |||||
// 收藏 | |||||
BlocProvider.of<GoodsDetailsFooterBloc>(context).add(GoodsDetailsFooterCollectEvent(model: model?.favArgs?.toJson())); | BlocProvider.of<GoodsDetailsFooterBloc>(context).add(GoodsDetailsFooterCollectEvent(model: model?.favArgs?.toJson())); | ||||
}else{ // 取消收藏 | |||||
} else { | |||||
// 取消收藏 | |||||
BlocProvider.of<GoodsDetailsFooterBloc>(context).add(GoodsDetailsFooterDeleteCollectEvent(model: model?.favArgs?.toJson())); | BlocProvider.of<GoodsDetailsFooterBloc>(context).add(GoodsDetailsFooterDeleteCollectEvent(model: model?.favArgs?.toJson())); | ||||
} | } | ||||
} | } | ||||
/// 分享 | /// 分享 | ||||
void _shareOnClick(GoodsDetailsFooterModel model) async { | void _shareOnClick(GoodsDetailsFooterModel model) async { | ||||
print(_user?.toString()); | |||||
if (_user?.token == null || _user.token == '') { | |||||
print('need login...'); | |||||
RouterUtil.goLogin(context); | |||||
return; | |||||
} | |||||
String d = widget.model['data']; | |||||
Map<String, dynamic> data = jsonDecode(d); | |||||
Map shareArgs = data['share_url_args'] ?? {}; | |||||
String shopType = shareArgs['type']; | |||||
// print(_user?.toString()); | |||||
// if (_user?.token == null || _user.token == '') { | |||||
// print('need login...'); | |||||
// RouterUtil.goLogin(context); | |||||
// return; | |||||
// } | |||||
// | |||||
// String d = widget.model['data']; | |||||
// Map<String, dynamic> data = jsonDecode(d); | |||||
// | |||||
// Map shareArgs = data['share_url_args'] ?? {}; | |||||
// String shopType = shareArgs['type']; | |||||
// | |||||
// if (data.containsKey('buy_url')) { | |||||
// String url = data['buy_url']; | |||||
// if (url == null || url == '') { | |||||
// Fluttertoast.showToast(msg: '购买链接不存在'); | |||||
// return; | |||||
// } | |||||
// if (shopType == 'taobao') { | |||||
// // bool isAuth = await TaobaoAuth.isAuth(); | |||||
// if (!_user.isTBAuth) { | |||||
// TaobaoAuth.auth(context); | |||||
// return; | |||||
// } | |||||
// } | |||||
// Navigator.of(context).push(CupertinoPageRoute( | |||||
// builder: (context) => GoodsSharePage(widget.model))); | |||||
// } | |||||
if (data.containsKey('buy_url')) { | |||||
String url = data['buy_url']; | |||||
if (url == null || url == '') { | |||||
Fluttertoast.showToast(msg: '购买链接不存在'); | |||||
return; | |||||
} | |||||
if (shopType == 'taobao') { | |||||
// bool isAuth = await TaobaoAuth.isAuth(); | |||||
if (!_user.isTBAuth) { | |||||
TaobaoAuth.auth(context); | |||||
return; | |||||
} | |||||
} | |||||
Navigator.of(context).push(CupertinoPageRoute( | |||||
builder: (context) => GoodsSharePage(widget.model))); | |||||
Map<String, dynamic> result = await TurnChainUtil.getShareTurnChain(context, _user, model.provider, model.convertArgs.toJson()); | |||||
if (!EmptyUtil.isEmpty(result)) { | |||||
model.shareUrlArgs.buyUrl = result['open_app_url']; | |||||
Navigator.of(context).push(CupertinoPageRoute(builder: (context) => GoodsSharePage(model.toJson()))); | |||||
} | } | ||||
} | } | ||||
/// 自购省 | /// 自购省 | ||||
void _savemoneyOnClick(GoodsDetailsFooterModel model) async { | |||||
print(_user?.toString()); | |||||
if (_user?.token == null || _user.token == '') { | |||||
print('need login...'); | |||||
RouterUtil.goLogin(context); | |||||
return; | |||||
} | |||||
String d = widget.model['data']; | |||||
Map<String, dynamic> data = jsonDecode(d); | |||||
Map shareArgs = data['share_url_args'] ?? {}; | |||||
String shopType = shareArgs['type']; | |||||
if (data.containsKey('buy_url')) { | |||||
String url = data['buy_url']; | |||||
if (url == null || url == '') { | |||||
Fluttertoast.showToast(msg: '购买链接不存在'); | |||||
return; | |||||
} | |||||
if (shopType == 'taobao') { | |||||
// bool isAuth = await TaobaoAuth.isAuth(); | |||||
if (!_user.isTBAuth) { | |||||
TaobaoAuth.auth(context); | |||||
return; | |||||
} | |||||
TradeResult result; | |||||
if (Platform.isAndroid) { | |||||
result = await FlutterAlibc.openByUrl(url: url, backUrl: "alisdk://"); | |||||
} else if (Platform.isIOS) { | |||||
result = await FlutterAlibc.openByUrl(url: url); | |||||
} | |||||
Logger.debug('${result.errorCode} ${result.errorMessage} '); | |||||
} else { | |||||
RouterUtil.openWebview(url, context); | |||||
} | |||||
} | |||||
void _saveMoneyOnClick(GoodsDetailsFooterModel model) async { | |||||
await TurnChainUtil.openReceiveCoupon(context, _user, model?.provider, model?.convertArgs?.toJson()); | |||||
} | } | ||||
@override | @override | ||||
@@ -188,8 +153,7 @@ class _GooddsDetailsFooterContainerState | |||||
return SafeArea( | return SafeArea( | ||||
child: Container( | child: Container( | ||||
width: double.infinity, | width: double.infinity, | ||||
padding: EdgeInsets.only( | |||||
bottom: (height > 10 ? 0 : 8), top: 8, left: 21, right: 12.5), | |||||
padding: EdgeInsets.only(bottom: (height > 10 ? 0 : 8), top: 8, left: 21, right: 12.5), | |||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
// boxShadow: [ | // boxShadow: [ | ||||
// BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0), blurRadius: 5.0, spreadRadius: 2.0), | // BoxShadow(color: Colors.grey[300], offset: Offset(0.0, 0.0), blurRadius: 5.0, spreadRadius: 2.0), | ||||
@@ -228,18 +192,14 @@ class _GooddsDetailsFooterContainerState | |||||
onTap: () => _openHome(), | onTap: () => _openHome(), | ||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(right: 35), | padding: const EdgeInsets.only(right: 35), | ||||
child: _getCustomWidget(model?.home ?? '首页', | |||||
model?.home_color ?? '999999', model?.home_icon ?? ''), | |||||
child: _getCustomWidget(model?.home ?? '首页', model?.home_color ?? '999999', model?.home_icon ?? ''), | |||||
)), | )), | ||||
GestureDetector( | GestureDetector( | ||||
behavior: HitTestBehavior.opaque, | behavior: HitTestBehavior.opaque, | ||||
onTap: () => _collectOnClick(model), | onTap: () => _collectOnClick(model), | ||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(right: 0), | padding: const EdgeInsets.only(right: 0), | ||||
child: _getCustomWidget( | |||||
model?.collect ?? '收藏', | |||||
model?.collect_color ?? '999999', | |||||
model?.isFav == '0' ? model?.collect_icon ?? '' : model?.collected_icon ?? ''))) | |||||
child: _getCustomWidget(model?.collect ?? '收藏', model?.collect_color ?? '999999', model?.isFav == '0' ? model?.collect_icon ?? '' : model?.collected_icon ?? ''))) | |||||
], | ], | ||||
); | ); | ||||
} | } | ||||
@@ -266,40 +226,30 @@ class _GooddsDetailsFooterContainerState | |||||
width: 110, | width: 110, | ||||
// padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | // padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
gradient: LinearGradient(colors: [ | |||||
HexColor.fromHex(model?.share_earn_bg1_color ?? '#FFCA66'), | |||||
HexColor.fromHex(model?.share_earn_bg2_color ?? '#FFD961') | |||||
], begin: Alignment.centerLeft, end: Alignment.centerRight), | |||||
borderRadius: BorderRadius.only( | |||||
bottomLeft: Radius.circular(25), topLeft: Radius.circular(25))), | |||||
gradient: LinearGradient( | |||||
colors: [HexColor.fromHex(model?.share_earn_bg1_color ?? '#FFCA66'), HexColor.fromHex(model?.share_earn_bg2_color ?? '#FFD961')], | |||||
begin: Alignment.centerLeft, | |||||
end: Alignment.centerRight), | |||||
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(25), topLeft: Radius.circular(25))), | |||||
child: Column( | child: Column( | ||||
crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
RichText( | RichText( | ||||
text: TextSpan( | |||||
text: '¥ ', | |||||
style: TextStyle( | |||||
fontSize: 12, | |||||
color: HexColor.fromHex( | |||||
model?.share_earn_val_color ?? 'FFFFFF')), | |||||
children: [ | |||||
TextSpan( | |||||
text: model?.share_value ?? '0.0', | |||||
style: TextStyle( | |||||
fontSize: 15, | |||||
fontWeight: FontWeight.bold, | |||||
color: HexColor.fromHex( | |||||
model?.share_earn_color ?? '#FFFFFF'), | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget')), | |||||
]), | |||||
text: TextSpan(text: '¥ ', style: TextStyle(fontSize: 12, color: HexColor.fromHex(model?.share_earn_val_color ?? 'FFFFFF')), children: [ | |||||
TextSpan( | |||||
text: model?.share_value ?? '0.0', | |||||
style: TextStyle( | |||||
fontSize: 15, | |||||
fontWeight: FontWeight.bold, | |||||
color: HexColor.fromHex(model?.share_earn_color ?? '#FFFFFF'), | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget')), | |||||
]), | |||||
), | ), | ||||
Text( | Text( | ||||
model?.share_earn ?? '分享赚', | model?.share_earn ?? '分享赚', | ||||
style: TextStyle( | |||||
color: HexColor.fromHex(model?.share_earn_color ?? '#FFFFFF'), | |||||
fontSize: 12), | |||||
style: TextStyle(color: HexColor.fromHex(model?.share_earn_color ?? '#FFFFFF'), fontSize: 12), | |||||
), | ), | ||||
], | ], | ||||
), | ), | ||||
@@ -311,49 +261,36 @@ class _GooddsDetailsFooterContainerState | |||||
Widget _getZgsButton(GoodsDetailsFooterModel model) { | Widget _getZgsButton(GoodsDetailsFooterModel model) { | ||||
return GestureDetector( | return GestureDetector( | ||||
behavior: HitTestBehavior.opaque, | behavior: HitTestBehavior.opaque, | ||||
onTap: () => _savemoneyOnClick(model), | |||||
onTap: () => _saveMoneyOnClick(model), | |||||
child: Container( | child: Container( | ||||
alignment: Alignment.center, | alignment: Alignment.center, | ||||
// padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | // padding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5), | ||||
height: 44, | height: 44, | ||||
width: 110, | width: 110, | ||||
decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
gradient: LinearGradient(colors: [ | |||||
HexColor.fromHex(model?.save_earn_bg1_color ?? '#FF6969'), | |||||
HexColor.fromHex(model?.save_earn_bg2_color ?? '#FF4646') | |||||
], begin: Alignment.centerLeft, end: Alignment.centerRight), | |||||
borderRadius: BorderRadius.only( | |||||
bottomRight: Radius.circular(25), | |||||
topRight: Radius.circular(25))), | |||||
gradient: LinearGradient( | |||||
colors: [HexColor.fromHex(model?.save_earn_bg1_color ?? '#FF6969'), HexColor.fromHex(model?.save_earn_bg2_color ?? '#FF4646')], | |||||
begin: Alignment.centerLeft, | |||||
end: Alignment.centerRight), | |||||
borderRadius: BorderRadius.only(bottomRight: Radius.circular(25), topRight: Radius.circular(25))), | |||||
child: Column( | child: Column( | ||||
crossAxisAlignment: CrossAxisAlignment.center, | crossAxisAlignment: CrossAxisAlignment.center, | ||||
mainAxisAlignment: MainAxisAlignment.center, | mainAxisAlignment: MainAxisAlignment.center, | ||||
children: <Widget>[ | children: <Widget>[ | ||||
RichText( | RichText( | ||||
text: TextSpan( | |||||
text: '¥ ', | |||||
style: TextStyle( | |||||
fontSize: 12, | |||||
color: HexColor.fromHex( | |||||
model?.save_earn_val_color ?? 'FFFFFF')), | |||||
children: [ | |||||
TextSpan( | |||||
text: model?.self_buy_value ?? '0.0', | |||||
style: TextStyle( | |||||
fontSize: 15, | |||||
fontWeight: FontWeight.bold, | |||||
color: HexColor.fromHex( | |||||
model?.save_earn_val_color ?? '#FFFFFF'), | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget', | |||||
)), | |||||
]), | |||||
text: TextSpan(text: '¥ ', style: TextStyle(fontSize: 12, color: HexColor.fromHex(model?.save_earn_val_color ?? 'FFFFFF')), children: [ | |||||
TextSpan( | |||||
text: model?.self_buy_value ?? '0.0', | |||||
style: TextStyle( | |||||
fontSize: 15, | |||||
fontWeight: FontWeight.bold, | |||||
color: HexColor.fromHex(model?.save_earn_val_color ?? '#FFFFFF'), | |||||
fontFamily: 'Din', | |||||
package: 'zhiying_base_widget', | |||||
)), | |||||
]), | |||||
), | ), | ||||
Text(model?.save_earn ?? '自购省', | |||||
style: TextStyle( | |||||
color: | |||||
HexColor.fromHex(model?.save_earn_color ?? '#FFFFFF'), | |||||
fontSize: 12)) | |||||
Text(model?.save_earn ?? '自购省', style: TextStyle(color: HexColor.fromHex(model?.save_earn_color ?? '#FFFFFF'), fontSize: 12)) | |||||
], | ], | ||||
), | ), | ||||
), | ), | ||||
@@ -376,8 +313,7 @@ class _GooddsDetailsFooterContainerState | |||||
const SizedBox(height: 5), | const SizedBox(height: 5), | ||||
/// 图片 | /// 图片 | ||||
Text(text, | |||||
style: TextStyle(color: HexColor.fromHex(textColor), fontSize: 11)) | |||||
Text(text, style: TextStyle(color: HexColor.fromHex(textColor), fontSize: 11)) | |||||
], | ], | ||||
); | ); | ||||
} | } | ||||
@@ -25,6 +25,10 @@ class GoodsDetailsFooterModel { | |||||
FavArgs favArgs; | FavArgs favArgs; | ||||
ShareUrlArgs shareUrlArgs; | ShareUrlArgs shareUrlArgs; | ||||
String provider; | |||||
String good_id; | |||||
ConvertArgs convertArgs; | |||||
GoodsDetailsFooterModel({ | GoodsDetailsFooterModel({ | ||||
this.buyUrl, | this.buyUrl, | ||||
this.favArgs, | this.favArgs, | ||||
@@ -50,6 +54,9 @@ class GoodsDetailsFooterModel { | |||||
this.share_value, | this.share_value, | ||||
this.self_buy_value, | this.self_buy_value, | ||||
this.collected_icon, | this.collected_icon, | ||||
this.good_id, | |||||
this.provider, | |||||
this.convertArgs, | |||||
}); | }); | ||||
factory GoodsDetailsFooterModel.fromJson(Map<String, dynamic> json) { | factory GoodsDetailsFooterModel.fromJson(Map<String, dynamic> json) { | ||||
@@ -78,6 +85,9 @@ class GoodsDetailsFooterModel { | |||||
share_value: json['share_value'], | share_value: json['share_value'], | ||||
self_buy_value: json['self_buy_value'], | self_buy_value: json['self_buy_value'], | ||||
collected_icon: json['collected_icon'], | collected_icon: json['collected_icon'], | ||||
good_id: json['good_id'], | |||||
provider: json['provider'], | |||||
convertArgs: json['convert_args'] != null ? ConvertArgs.fromJson(json['convert_args']) : null, | |||||
); | ); | ||||
} | } | ||||
@@ -113,6 +123,12 @@ class GoodsDetailsFooterModel { | |||||
data['share_url_args'] = this.shareUrlArgs.toJson(); | data['share_url_args'] = this.shareUrlArgs.toJson(); | ||||
} | } | ||||
data['provider'] = this.provider; | |||||
data['good_id'] = this.good_id; | |||||
if (this.convertArgs != null) { | |||||
data['convert_args'] = this.convertArgs.toJson(); | |||||
} | |||||
return data; | return data; | ||||
} | } | ||||
} | } | ||||
@@ -218,3 +234,34 @@ class ShareUrlArgs { | |||||
return data; | return data; | ||||
} | } | ||||
} | } | ||||
class ConvertArgs { | |||||
String gid; | |||||
String goodUrl; | |||||
String couponUrl; | |||||
String couponPrice; | |||||
String activityUrl; | |||||
String isShare; | |||||
ConvertArgs({this.gid, this.goodUrl, this.couponUrl, this.couponPrice, this.activityUrl, this.isShare}); | |||||
ConvertArgs.fromJson(Map<String, dynamic> json) { | |||||
gid = json['gid']; | |||||
goodUrl = json['good_url']; | |||||
couponUrl = json['coupon_url']; | |||||
couponPrice = json['coupon_price']; | |||||
activityUrl = json['activity_url']; | |||||
isShare = json['is_share']; | |||||
} | |||||
Map<String, dynamic> toJson() { | |||||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||||
data['gid'] = this.gid; | |||||
data['good_url'] = this.goodUrl; | |||||
data['coupon_url'] = this.couponUrl; | |||||
data['coupon_price'] = this.couponPrice; | |||||
data['activity_url'] = this.activityUrl; | |||||
data['is_share'] = this.isShare; | |||||
return data; | |||||
} | |||||
} |
@@ -30,10 +30,10 @@ class HomeQuickEntryContianer extends StatefulWidget { | |||||
} | } | ||||
class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | ||||
/// Icon点击事件 | /// Icon点击事件 | ||||
void _itemIconClick(TypeNormal model){ | |||||
void _itemIconClick(TypeNormal model) { | |||||
print("item type = ${model.skip_identifier}"); | print("item type = ${model.skip_identifier}"); | ||||
// Navigator.push(context, CupertinoPageRoute(builder: (_) => CommonPage(null))); | |||||
RouterUtil.route(model, model.toJson(), context); | RouterUtil.route(model, model.toJson(), context); | ||||
} | } | ||||
@@ -62,7 +62,6 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
} | } | ||||
Widget _getMainWidget(HomeQuickEntryModel model) { | Widget _getMainWidget(HomeQuickEntryModel model) { | ||||
// 数据总数 | // 数据总数 | ||||
int totalDataSize = model?.type_normal?.length ?? 0; | int totalDataSize = model?.type_normal?.length ?? 0; | ||||
@@ -97,15 +96,16 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
// 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度 | // 总体高度 = 行数 * (子元素高度 + 边距高度) + 进度条的高度 | ||||
double totalHeight = totalRowSize * (itemHeight + barMargin) + 4; | double totalHeight = totalRowSize * (itemHeight + barMargin) + 4; | ||||
if(!EmptyUtil.isEmpty(model?.pagination_open) && model.pagination_open == '0') { | |||||
totalHeight = totalRowSize * (itemHeight + barMargin); | |||||
if (!EmptyUtil.isEmpty(model?.pagination_open) && model.pagination_open == '0') { | |||||
totalHeight = totalRowSize * (itemHeight + barMargin); | |||||
} | } | ||||
return Container( | return Container( | ||||
color: Colors.white, | color: Colors.white, | ||||
child: Container( | child: Container( | ||||
margin: EdgeInsets.only(top: 15, bottom: totalPage >1 ? 15 : 0 ), | |||||
height: totalHeight, // 总体高度 | |||||
margin: EdgeInsets.only(top: 15, bottom: totalPage > 1 ? 15 : 0), | |||||
height: totalHeight, | |||||
// 总体高度 | |||||
width: double.infinity, | width: double.infinity, | ||||
color: Colors.white, | color: Colors.white, | ||||
child: Swiper( | child: Swiper( | ||||
@@ -122,7 +122,7 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
totalDataSize: totalDataSize, | totalDataSize: totalDataSize, | ||||
totalPage: totalPage, | totalPage: totalPage, | ||||
currentPage: index, | currentPage: index, | ||||
totalRowSize: totalRowSize, | |||||
totalRowSize: totalRowSize, | |||||
columSize: columSize, | columSize: columSize, | ||||
model: model, | model: model, | ||||
itemHeight: itemHeight, | itemHeight: itemHeight, | ||||
@@ -136,47 +136,87 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
} | } | ||||
/// 页的数据 | /// 页的数据 | ||||
Widget _getPageWidget({double titleHeight, double iconHeight, int totalPage, int currentPage, int columSize, int totalRowSize, int totalDataSize, HomeQuickEntryModel model,double itemHeight}){ | |||||
Widget _getPageWidget( | |||||
{double titleHeight, double iconHeight, int totalPage, int currentPage, int columSize, int totalRowSize, int totalDataSize, HomeQuickEntryModel model, double itemHeight}) { | |||||
List rowList = []; | List rowList = []; | ||||
for(int i = 0 ; i < totalRowSize; i ++){ | |||||
for (int i = 0; i < totalRowSize; i++) { | |||||
rowList.add(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(), | |||||
); | |||||
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, HomeQuickEntryModel model, int currentRow, double itemHeight}) { | |||||
Widget _getRowWidget( | |||||
{double titleHeight, | |||||
double iconHeight, | |||||
int totalPage, | |||||
int currentPage, | |||||
int columSize, | |||||
int totalRowSize, | |||||
int totalDataSize, | |||||
HomeQuickEntryModel model, | |||||
int currentRow, | |||||
double itemHeight}) { | |||||
List itemList = []; | List itemList = []; | ||||
for(int i = 0; i < columSize; i++){ | |||||
for (int i = 0; i < columSize; i++) { | |||||
itemList.add(i); | itemList.add(i); | ||||
} | } | ||||
return Row( | return Row( | ||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||
crossAxisAlignment: CrossAxisAlignment.center, | 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,); | |||||
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(), | }).toList(), | ||||
); | ); | ||||
} | } | ||||
/// item 的数据 | /// item 的数据 | ||||
Widget _getColumWidget({double titleHeight, double iconHeight, int totalPage, int currentPage, int columSize, int totalRowSize, int totalDataSize, HomeQuickEntryModel model, int currentRow,int currentColum, double itemHeight}){ | |||||
Widget _getColumWidget( | |||||
{double titleHeight, | |||||
double iconHeight, | |||||
int totalPage, | |||||
int currentPage, | |||||
int columSize, | |||||
int totalRowSize, | |||||
int totalDataSize, | |||||
HomeQuickEntryModel model, | |||||
int currentRow, | |||||
int currentColum, | |||||
double itemHeight}) { | |||||
// 当前index = 当前的页数+1 * 当前的行数 + 当前的列数 | // 当前index = 当前的页数+1 * 当前的行数 + 当前的列数 | ||||
// int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize; | // int currentIndex = (currentPage + 1) * currentRow + currentColum + currentRow*columSize; | ||||
// int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize : | // int currentIndex = currentPage != 0 ? currentPage * (columSize * totalRowSize) + columSize + currentRow * columSize : | ||||
@@ -187,22 +227,24 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
// print('current Index sss = $currentIndex'); | // print('current Index sss = $currentIndex'); | ||||
if(currentIndex >= totalDataSize){ | |||||
return Container( height: itemHeight, width: 60,); | |||||
if (currentIndex >= totalDataSize) { | |||||
return Container( | |||||
height: itemHeight, | |||||
width: 60, | |||||
); | |||||
} | } | ||||
TypeNormal item = model?.type_normal[currentIndex]; | TypeNormal item = model?.type_normal[currentIndex]; | ||||
return GestureDetector( | return GestureDetector( | ||||
behavior: HitTestBehavior.opaque, | behavior: HitTestBehavior.opaque, | ||||
onTap: ()=> _itemIconClick(item), | |||||
onTap: () => _itemIconClick(item), | |||||
child: Container( | child: Container( | ||||
height: itemHeight, | height: itemHeight, | ||||
width: 60, | width: 60, | ||||
// color: Colors.red, | // color: Colors.red, | ||||
child: Column( | child: Column( | ||||
children: <Widget>[ | children: <Widget>[ | ||||
/// 图标 | /// 图标 | ||||
MyNetWorkImage(item.img), | MyNetWorkImage(item.img), | ||||
@@ -211,7 +253,10 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
visible: !EmptyUtil.isEmpty(model?.title_1_open) && model.title_1_open == '1', | visible: !EmptyUtil.isEmpty(model?.title_1_open) && model.title_1_open == '1', | ||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(top: 5), | padding: const EdgeInsets.only(top: 5), | ||||
child: Text(item?.title_1 ?? '', style: TextStyle( fontSize: 10, color: HexColor.fromHex(model?.title_1_text_color)),), | |||||
child: Text( | |||||
item?.title_1 ?? '', | |||||
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.title_1_text_color)), | |||||
), | |||||
), | ), | ||||
), | ), | ||||
@@ -220,36 +265,39 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
visible: !EmptyUtil.isEmpty(model?.title_2_open) && model.title_2_open == '1', | visible: !EmptyUtil.isEmpty(model?.title_2_open) && model.title_2_open == '1', | ||||
child: Padding( | child: Padding( | ||||
padding: const EdgeInsets.only(top: 5), | padding: const EdgeInsets.only(top: 5), | ||||
child: Text(item?.title_2 ?? '', style: TextStyle( fontSize: 10, color: HexColor.fromHex(model?.title_2_text_color)),), | |||||
child: Text( | |||||
item?.title_2 ?? '', | |||||
style: TextStyle(fontSize: 10, color: HexColor.fromHex(model?.title_2_text_color)), | |||||
), | |||||
), | ), | ||||
) | ) | ||||
], | ], | ||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
/// 进度条 | /// 进度条 | ||||
SwiperPagination _getSwiperPaginationContorl(HomeQuickEntryModel model, int pageCount){ | |||||
if(EmptyUtil.isEmpty(model?.pagination_open) || model.pagination_open == '0'){ | |||||
SwiperPagination _getSwiperPaginationContorl(HomeQuickEntryModel model, int pageCount) { | |||||
if (EmptyUtil.isEmpty(model?.pagination_open) || model.pagination_open == '0') { | |||||
return null; | return null; | ||||
} | } | ||||
if(model.pagination == 'type_point'){ | |||||
if (model.pagination == 'type_point') { | |||||
// 点点点进度条 | // 点点点进度条 | ||||
return _swiperPaginationDot(model); | return _swiperPaginationDot(model); | ||||
}else{ | |||||
} else { | |||||
// 自定义进度条 | // 自定义进度条 | ||||
return _swiperCustomPagination(pageCount); | return _swiperCustomPagination(pageCount); | ||||
} | } | ||||
} | } | ||||
// 进度条 圆形 | // 进度条 圆形 | ||||
SwiperPagination _swiperPaginationDot(HomeQuickEntryModel model){ | |||||
return SwiperPagination(margin: const EdgeInsets.only(), builder: DotSwiperPaginationBuilder( color: HexColor.fromHex(model?.pagination_unselect_color), activeColor: HexColor.fromHex(model?.pagination_select_color), size: 8, activeSize: 8)); | |||||
SwiperPagination _swiperPaginationDot(HomeQuickEntryModel model) { | |||||
return SwiperPagination( | |||||
margin: const EdgeInsets.only(), | |||||
builder: DotSwiperPaginationBuilder( | |||||
color: HexColor.fromHex(model?.pagination_unselect_color), activeColor: HexColor.fromHex(model?.pagination_select_color), size: 8, activeSize: 8)); | |||||
} | } | ||||
// 自定义进度条 条形 | // 自定义进度条 条形 | ||||
@@ -294,9 +342,9 @@ class _HomeQuickEntryContianerState extends State<HomeQuickEntryContianer> { | |||||
/// 图片build 优化 | /// 图片build 优化 | ||||
/// | /// | ||||
class MyNetWorkImage extends StatelessWidget { | class MyNetWorkImage extends StatelessWidget { | ||||
final String imgUrl; | final String imgUrl; | ||||
final double width; | final double width; | ||||
const MyNetWorkImage(this.imgUrl, {this.width = 40}); | const MyNetWorkImage(this.imgUrl, {this.width = 40}); | ||||
@override | @override | ||||
@@ -71,11 +71,11 @@ class _HomeSreachContainer extends StatelessWidget { | |||||
/// 打开搜索页 | /// 打开搜索页 | ||||
void _openSreach(BuildContext context){ | void _openSreach(BuildContext context){ | ||||
// SkipModel skipModel = SkipModel.fromJson(model); | |||||
// RouterUtil.route(skipModel, null, context); | |||||
Navigator.push(context, CupertinoPageRoute( | |||||
builder: (context) => SearchPage(null) | |||||
)); | |||||
SkipModel skipModel = SkipModel.fromJson(model); | |||||
RouterUtil.route(skipModel, skipModel.toJson(), context); | |||||
// Navigator.push(context, CupertinoPageRoute( | |||||
// builder: (context) => SearchPage(null) | |||||
// )); | |||||
} | } | ||||
@override | @override | ||||
@@ -80,7 +80,7 @@ class _ShareAlertContentState extends State<_ShareAlertContent> { | |||||
Map d = modList.first; | Map d = modList.first; | ||||
if (d != null) { | if (d != null) { | ||||
String dString = d['data']; | String dString = d['data']; | ||||
List list = jsonDecode(dString); | |||||
List list = jsonDecode(dString)['list']; | |||||
_icons = list.map((item) { | _icons = list.map((item) { | ||||
return ShareIconModel.fromJson(Map<String, dynamic>.from(item)); | return ShareIconModel.fromJson(Map<String, dynamic>.from(item)); | ||||
}).toList(); | }).toList(); | ||||
@@ -36,40 +36,27 @@ class WalletBilDetailSkeleton extends StatelessWidget { | |||||
height: 16, | height: 16, | ||||
), | ), | ||||
Row( | Row( | ||||
mainAxisAlignment: MainAxisAlignment.start, | |||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, | |||||
children: <Widget>[ | children: <Widget>[ | ||||
SizedBox( | |||||
width: 16, | |||||
), | |||||
Container( | Container( | ||||
color: Colors.white, | color: Colors.white, | ||||
height: 40, | height: 40, | ||||
width: 80, | width: 80, | ||||
), | ), | ||||
SizedBox( | |||||
width: 16, | |||||
), | |||||
Container( | Container( | ||||
color: Colors.white, | color: Colors.white, | ||||
height: 40, | height: 40, | ||||
width: 80, | width: 80, | ||||
), | ), | ||||
SizedBox( | |||||
width: 16, | |||||
), | |||||
Container( | Container( | ||||
color: Colors.white, | color: Colors.white, | ||||
height: 40, | height: 40, | ||||
width: 80, | width: 80, | ||||
), | ), | ||||
SizedBox( | |||||
width: 16, | |||||
), | |||||
Container( | |||||
color: Colors.white, | |||||
height: 40, | |||||
width: 80, | |||||
) | |||||
], | ], | ||||
), | ), | ||||
Expanded( | Expanded( | ||||