@@ -22,10 +22,29 @@ class FeedbackBloc extends Bloc<FeedbackEvent, FeedbackState> { | |||
if (event is FeedbackInitEvent) { | |||
yield* _mapInitToState(event); | |||
} | |||
/// 提交反馈 | |||
if (event is FeedbackSubmitEvent) { | |||
yield* _mapSaveToState(event); | |||
} | |||
} | |||
/// 提交反馈 | |||
Stream<FeedbackState> _mapSaveToState(FeedbackSubmitEvent event) async* { | |||
var result = await repository.saveFeedback(event?.model); | |||
if (!EmptyUtil.isEmpty(result)) { | |||
yield FeedbackSaveSuccessState(); | |||
} else { | |||
yield FeedbackSaveErrorState(); | |||
} | |||
} | |||
/// 初始化 | |||
Stream<FeedbackState> _mapInitToState(FeedbackInitEvent event) async* { | |||
var cache = await repository.fetchCachedData(event.model); | |||
if (!EmptyUtil.isEmpty(cache)) { | |||
yield FeedbackLoadedState(model: cache); | |||
} | |||
var result = await repository.fetchData(event.model); | |||
if (!EmptyUtil.isEmpty(result)) { | |||
yield FeedbackLoadedState(model: result); | |||
@@ -10,4 +10,8 @@ class FeedbackInitEvent extends FeedbackEvent{ | |||
} | |||
/// 提交反馈 | |||
class FeedbackSubmitEvent extends FeedbackEvent{} | |||
class FeedbackSubmitEvent extends FeedbackEvent{ | |||
final Map<String, dynamic> model; | |||
FeedbackSubmitEvent({this.model}); | |||
} |
@@ -0,0 +1,73 @@ | |||
import 'dart:async'; | |||
import 'package:bloc/bloc.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_repository.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'feedback_record_event.dart'; | |||
import 'feedback_record_state.dart'; | |||
class FeedbackRecordBloc extends Bloc<FeedbackRecordEvent, FeedbackRecordState> { | |||
// FeedbackRecordBloc() : super(FeedbackRecordInitial()); | |||
@override | |||
FeedbackRecordState get initialState => FeedbackRecordInitial(); | |||
FeedbackRecordRepository repository; | |||
FeedbackRecordBloc(this.repository); | |||
@override | |||
Stream<FeedbackRecordState> mapEventToState( | |||
FeedbackRecordEvent event, | |||
) async* { | |||
/// 初始化 | |||
if (event is FeedbackRecordInitEvent) { | |||
yield* _mapInitEventToState(event); | |||
} | |||
/// 刷新 | |||
if (event is FeedbackRecordRefreshEvent) { | |||
yield* _mapRefreshEventToState(event); | |||
} | |||
/// 加载更多 | |||
if (event is FeedbackRecordLoadEvent) { | |||
yield* _mapLoadEventToState(event); | |||
} | |||
} | |||
/// 初始化 | |||
Stream<FeedbackRecordState> _mapInitEventToState(FeedbackRecordInitEvent event) async* { | |||
var styleCache = await repository.fetchCacheStyle(); | |||
var styleNet = await repository.fetchInitStyle(); | |||
var data = await repository.fetchInitData(); | |||
if (!EmptyUtil.isEmpty(data) && (!EmptyUtil.isEmpty(styleCache) || !EmptyUtil.isEmpty(styleNet))) { | |||
yield FeedbackRecordLoadedState(dataModel: data, styleModel: !EmptyUtil.isEmpty(styleNet) ? styleNet : styleCache); | |||
} else { | |||
yield FeedbackRecordInitErrorState(); | |||
} | |||
} | |||
/// 刷新 | |||
Stream<FeedbackRecordState> _mapRefreshEventToState(FeedbackRecordRefreshEvent event) async* { | |||
var style = repository.styleModel; | |||
var result = await repository.fetchRefreshData(); | |||
if (!EmptyUtil.isEmpty(result) && !EmptyUtil.isEmpty(style)) { | |||
yield FeedbackRecordRefreshSuccessState(); | |||
yield FeedbackRecordLoadedState(dataModel: result, styleModel: style); | |||
} else { | |||
yield FeedbackRecordRefreshErrorState(); | |||
} | |||
} | |||
/// 加载更多 | |||
Stream<FeedbackRecordState> _mapLoadEventToState(FeedbackRecordLoadEvent event) async* { | |||
var style = repository.styleModel; | |||
var result = await repository.fetchLoadData(); | |||
if (!EmptyUtil.isEmpty(result) && !EmptyUtil.isEmpty(style)) { | |||
yield FeedbackRecordLoadSuccessState(); | |||
yield FeedbackRecordLoadedState(dataModel: result, styleModel: style); | |||
} else { | |||
yield FeedbackRecordLoadErrorState(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
import 'package:meta/meta.dart'; | |||
@immutable | |||
abstract class FeedbackRecordEvent {} | |||
/// 初始化 | |||
class FeedbackRecordInitEvent extends FeedbackRecordEvent {} | |||
/// 下拉刷新 | |||
class FeedbackRecordRefreshEvent extends FeedbackRecordEvent {} | |||
/// 加载更多 | |||
class FeedbackRecordLoadEvent extends FeedbackRecordEvent {} |
@@ -0,0 +1,117 @@ | |||
import 'dart:convert'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class FeedbackRecordRepository { | |||
// final int max = 5; | |||
int _currentPage = 1; | |||
bool _hasMore = true; | |||
final Map<String, dynamic> data; | |||
FeedbackRecordRepository(this.data) { | |||
_dataModel = FeedbackRecordDataModel(); | |||
_dataModel.data = []; | |||
} | |||
/// 样式数据 | |||
FeedbackRecordStyleModel _styleModel; | |||
/// 数据 | |||
FeedbackRecordDataModel _dataModel; | |||
FeedbackRecordStyleModel get styleModel => _styleModel; | |||
FeedbackRecordDataModel get dataModel => _dataModel; | |||
/// 初始化数据 | |||
Future<dynamic> fetchInitData() async { | |||
_hasMore = true; | |||
_currentPage = 1; | |||
return _fetchBaseRequest(); | |||
} | |||
/// 样式初始化 | |||
Future<dynamic> fetchInitStyle() async { | |||
try { | |||
String skipIdentifier = | |||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback_list'; | |||
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); | |||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
return _handleStyle(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]); | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
/// 获取缓存样式 | |||
Future<dynamic> fetchCacheStyle() async { | |||
try { | |||
String skipIdentifier = | |||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback_list'; | |||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); | |||
if (!EmptyUtil.isEmpty(result)) { | |||
return _handleStyle(result); | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
/// 处理样式 | |||
dynamic _handleStyle(Map<String, dynamic> data) { | |||
try { | |||
var modListData = data['mod_list'][0]['data']; | |||
if (!EmptyUtil.isEmpty(modListData)) { | |||
FeedbackRecordStyleModel model = FeedbackRecordStyleModel.fromJson(modListData is String ? jsonDecode(modListData) : modListData); | |||
if (!EmptyUtil.isEmpty(model)) { | |||
_styleModel = model; | |||
return _styleModel; | |||
} | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
/// 刷新 | |||
Future<dynamic> fetchRefreshData() async { | |||
_hasMore = true; | |||
_currentPage = 1; | |||
return _fetchBaseRequest(); | |||
} | |||
/// 加载更多 | |||
Future<dynamic> fetchLoadData() async { | |||
if (_hasMore) { | |||
return _fetchBaseRequest(); | |||
} | |||
return null; | |||
} | |||
/// 基础加载方法 | |||
Future<dynamic> _fetchBaseRequest() async { | |||
try { | |||
var result = await NetUtil.post('/api/v1/feedback/list', method: NetMethod.GET, queryParameters: {'page': _currentPage.toString()}); | |||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
FeedbackRecordDataModel model = FeedbackRecordDataModel.fromJson(result); | |||
if (!EmptyUtil.isEmpty(model) && !EmptyUtil.isEmpty(model?.data)) { | |||
_dataModel.data.addAll(model.data); | |||
_hasMore = true; | |||
++_currentPage; | |||
return _dataModel; | |||
} | |||
} | |||
_hasMore = false; | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
import 'package:meta/meta.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||
@immutable | |||
abstract class FeedbackRecordState {} | |||
class FeedbackRecordInitial extends FeedbackRecordState {} | |||
/// 数据加载成功 | |||
class FeedbackRecordLoadedState extends FeedbackRecordState { | |||
FeedbackRecordDataModel dataModel; | |||
FeedbackRecordStyleModel styleModel; | |||
FeedbackRecordLoadedState({this.dataModel, this.styleModel}); | |||
} | |||
/// 初始化失败 | |||
class FeedbackRecordInitErrorState extends FeedbackRecordState{} | |||
/// 刷新成功与失败 | |||
class FeedbackRecordRefreshSuccessState extends FeedbackRecordState{} | |||
class FeedbackRecordRefreshErrorState extends FeedbackRecordState{} | |||
/// 加载更多成功与失败 | |||
class FeedbackRecordLoadSuccessState extends FeedbackRecordState{} | |||
class FeedbackRecordLoadErrorState extends FeedbackRecordState{} |
@@ -1,21 +1,42 @@ | |||
import 'dart:convert'; | |||
import 'dart:io'; | |||
import 'package:path/path.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class FeedBackRepository { | |||
/// 获取缓存样式数据 | |||
Future<FeedbackModel> fetchCachedData(final Map<String, dynamic> data) async { | |||
try { | |||
String skipIdentifier = | |||
!EmptyUtil.isEmpty(data) && data.containsKey('skip_identifier') && !EmptyUtil.isEmpty(data['skip_identifier']) ? data['skip_identifier'] : 'pub.flutter.feedback'; | |||
var result = await NetUtil.getRequestCachedData('/api/v1/mod/$skipIdentifier'); | |||
if (!EmptyUtil.isEmpty(result)) { | |||
var modListData = result['mod_list'][0]['data']; | |||
if (!EmptyUtil.isEmpty(modListData)) { | |||
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | |||
model.feedbackTypes.last.isSelect = true; | |||
return model; | |||
} | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
/// 获取网络样式数据 | |||
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'; | |||
String skipIdentifier = | |||
!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); | |||
var result = await NetUtil.post('/api/v1/mod/$skipIdentifier', method: NetMethod.GET, cache: true); | |||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
var modListData = result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['mod_list'][0]['data']; | |||
if (!EmptyUtil.isEmpty(modListData)) { | |||
FeedbackModel model = FeedbackModel.fromJson(jsonDecode(modListData)); | |||
model.feedbackTypes.last.isSelect = true; | |||
return model; | |||
} | |||
} | |||
@@ -25,6 +46,71 @@ class FeedBackRepository { | |||
return null; | |||
} | |||
/// 获取网络数据 | |||
/// 提交反馈 | |||
Future<dynamic> saveFeedback(final Map<String, dynamic> data) async { | |||
try { | |||
List<File> files = data['files']; | |||
List<String> imageList = []; | |||
if(!EmptyUtil.isEmpty(files)) { | |||
// files.forEach((element) async { | |||
// String fileName = await updateFile(element); | |||
// if (!EmptyUtil.isEmpty(fileName)) { | |||
// imageList.add(fileName); | |||
// } | |||
// }); | |||
for(int i = 0 ; i < files.length; i++){ | |||
String imgName = await updateFile(files[i]); | |||
if(!EmptyUtil.isEmpty(imgName)){ | |||
imageList.add(imgName); | |||
} | |||
} | |||
if (imageList.length != files.length) { | |||
return null; | |||
} | |||
} | |||
var result = await NetUtil.post('/api/v1/feedback/save', method: NetMethod.POST, params: { | |||
'type': data['type']?.toString(), | |||
'title': data['title']?.toString(), | |||
'content': data['content']?.toString(), | |||
'image_list': imageList, | |||
}); | |||
if (NetUtil.isSuccess(result) && !EmptyUtil.isEmpty(result[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
return result[GlobalConfig.HTTP_RESPONSE_KEY_DATA]; | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
/// 上传图片 | |||
Future<String> updateFile(final File imageFile) async { | |||
try { | |||
List<int> originBytes = await imageFile.readAsBytes(); | |||
var result1 = await NetUtil.post('/api/v1/img/upload', params: {'dir': 'feedback', 'file_size': originBytes.length, 'file_name': basename(imageFile.path)}, method: NetMethod.PUT); | |||
if (NetUtil.isSuccess(result1) && !EmptyUtil.isEmpty(result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]) && !EmptyUtil.isEmpty(result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['token'])) { | |||
String token = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['token']; | |||
String host = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['host']; | |||
String key = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['key']; | |||
String method = result1[GlobalConfig.HTTP_RESPONSE_KEY_DATA]['method']; | |||
var result2 = await NetUtil.uploadFile(host, imageFile, params: {'key': key, 'token': token}, method: method); | |||
Map<String, dynamic> json = jsonDecode(result2.toString()); | |||
if (NetUtil.isSuccess(json) && !EmptyUtil.isEmpty(json[GlobalConfig.HTTP_RESPONSE_KEY_DATA])) { | |||
String filename = json['data']['fname'] ?? ''; | |||
print(filename); | |||
// filename += '?${DateTime.now().millisecondsSinceEpoch.toString()}'; | |||
// print(filename); | |||
// ⚠️ 这里返回key是因为fname是带有域名的,所以直接用key即可 | |||
return !EmptyUtil.isEmpty(filename) ? key : null; | |||
} | |||
} | |||
} catch (e, s) { | |||
Logger.error(e, s); | |||
} | |||
return null; | |||
} | |||
} |
@@ -13,3 +13,9 @@ class FeedbackLoadedState extends FeedbackState{ | |||
} | |||
class FeedbackErrorState extends FeedbackState{} | |||
/// 保存反馈成功 | |||
class FeedbackSaveSuccessState extends FeedbackState{} | |||
/// 保存反馈失败 | |||
class FeedbackSaveErrorState extends FeedbackState{} |
@@ -1,4 +1,5 @@ | |||
import 'dart:io'; | |||
import 'dart:math'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:flutter/material.dart'; | |||
@@ -55,6 +56,9 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
TextEditingController _title; | |||
// 是否上传中 | |||
bool isUpLoading = false; | |||
@override | |||
void initState() { | |||
_feedback = TextEditingController(); | |||
@@ -69,7 +73,6 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
super.dispose(); | |||
} | |||
/// 选择图片 | |||
void _onAddImage() async { | |||
if (_images.length >= 4) { | |||
@@ -107,9 +110,13 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
if (file == null) return; | |||
setState(() { | |||
_images.add(File(file.path)); | |||
}); | |||
if (_images.length <= 4) { | |||
setState(() { | |||
_images.add(File(file.path)); | |||
}); | |||
} else { | |||
Fluttertoast.showToast(msg: '最多只能选择4张'); | |||
} | |||
// File resultFile = await EncodeUtil.compressImage(file, 800); | |||
} | |||
@@ -120,6 +127,19 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
return BlocConsumer<FeedbackBloc, FeedbackState>( | |||
listener: (context, state) {}, | |||
buildWhen: (prev, current) { | |||
/// 保存成功 | |||
if (current is FeedbackSaveSuccessState) { | |||
Fluttertoast.showToast(msg: '反馈成功~'); | |||
Navigator.pop(context); | |||
return false; | |||
} | |||
if (current is FeedbackSaveErrorState) { | |||
Fluttertoast.showToast(msg: '反馈失败~'); | |||
setState(() { | |||
isUpLoading = false; | |||
}); | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
@@ -169,14 +189,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
Center( | |||
child: GestureDetector( | |||
behavior: HitTestBehavior.opaque, | |||
onTap: () { | |||
Navigator.push( | |||
context, | |||
CupertinoPageRoute( | |||
builder: (_) => FeedbackRecordPage(), | |||
), | |||
); | |||
}, | |||
onTap: () => RouterUtil.route(model, model.toJson(), context), | |||
child: Container( | |||
width: 120, | |||
height: 30, | |||
@@ -273,6 +286,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
), | |||
), | |||
const SizedBox(height: 2), | |||
/// 异常选项 | |||
Padding( | |||
padding: EdgeInsets.only(top: 4, bottom: 4), | |||
@@ -281,16 +295,15 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
child: Row( | |||
children: model.feedbackTypes | |||
.map((e) => Expanded( | |||
child: GestureDetector( | |||
child: GestureDetector( | |||
behavior: HitTestBehavior.opaque, | |||
onTap: (){ | |||
onTap: () { | |||
setState(() { | |||
model.feedbackTypes.forEach((element) { | |||
element.isSelect = false; | |||
}); | |||
e.isSelect = true; | |||
}); | |||
}, | |||
child: Container( | |||
margin: EdgeInsets.only(left: 2, right: 2), | |||
@@ -311,9 +324,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
e.name ?? '', | |||
style: TextStyle( | |||
fontSize: 12, | |||
color: HexColor.fromHex(e.isSelect | |||
? model?.feedbackTypeSelectedTextColor | |||
: model?.feedbackTypeNoSelectedTextColor) //e.isSelect ? Colors.redAccent : Color(0xff999999), | |||
color: HexColor.fromHex( | |||
e.isSelect ? model?.feedbackTypeSelectedTextColor : model?.feedbackTypeNoSelectedTextColor) //e.isSelect ? Colors.redAccent : Color(0xff999999), | |||
), | |||
), | |||
), | |||
@@ -401,8 +413,9 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
child: FeedbackImageWidget( | |||
file: file, | |||
onDelete: () { | |||
_images.remove(file); | |||
setState(() {}); | |||
setState(() { | |||
_images.remove(file); | |||
}); | |||
}, | |||
), | |||
)); | |||
@@ -425,6 +438,8 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
} | |||
return Column( | |||
mainAxisAlignment: MainAxisAlignment.center, | |||
crossAxisAlignment: CrossAxisAlignment.start, | |||
children: <Widget>[ | |||
Row( | |||
children: <Widget>[ | |||
@@ -448,9 +463,18 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
), | |||
], | |||
), | |||
Row( | |||
// Row( | |||
// children: images, | |||
// ) | |||
Wrap( | |||
crossAxisAlignment: WrapCrossAlignment.center, | |||
textDirection: TextDirection.ltr, | |||
spacing: 0, | |||
runSpacing: 0, | |||
runAlignment: WrapAlignment.center, | |||
alignment: WrapAlignment.start, | |||
children: images, | |||
) | |||
), | |||
], | |||
); | |||
} | |||
@@ -461,9 +485,27 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
if (!_submitable) { | |||
return; | |||
} | |||
if(isUpLoading){ | |||
// Fluttertoast.showToast(msg: '提交中...'); | |||
return; | |||
} | |||
setState(() { | |||
isUpLoading = true; | |||
}); | |||
Logger.debug('提交:${_feedback.text.toString()}'); | |||
Fluttertoast.showToast(msg: '提交成功~'); | |||
Navigator.pop(context); | |||
String selectId; | |||
model.feedbackTypes.forEach((element) { | |||
if (element.isSelect) { | |||
selectId = element.typeId; | |||
} | |||
}); | |||
BlocProvider.of<FeedbackBloc>(context) | |||
.add(FeedbackSubmitEvent(model: {'title': _title?.text?.toString(), 'content': _feedback?.text?.toString(), 'type': selectId, 'files': _images})); | |||
// Fluttertoast.showToast(msg: '提交成功~'); | |||
// Navigator.pop(context); | |||
}, | |||
child: Container( | |||
margin: EdgeInsets.only(top: 24, bottom: 4), | |||
@@ -474,7 +516,7 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
), | |||
child: Center( | |||
child: Text( | |||
model?.feedbackPostBtnText ?? '提交意见', | |||
isUpLoading ? '提交意见...' : model?.feedbackPostBtnText ?? '提交意见', | |||
style: TextStyle( | |||
fontSize: 14, | |||
color: HexColor.fromHex(model?.feedbackPostBtnTextColor ?? '#FFFFFF'), | |||
@@ -484,6 +526,4 @@ class __FeedbackPageContainerState extends State<_FeedbackPageContainer> { | |||
), | |||
); | |||
} | |||
} |
@@ -1,36 +1,167 @@ | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_bloc.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/bloc/feedback_record_repository.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/widgets/feedback_record_item.dart'; | |||
import 'package:zhiying_base_widget/widgets/empty/empty_widget.dart'; | |||
import 'package:flutter_bloc/flutter_bloc.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'bloc/feedback_record_event.dart'; | |||
import 'bloc/feedback_record_state.dart'; | |||
class FeedbackRecordPage extends StatelessWidget { | |||
final Map<String, dynamic> data; | |||
FeedbackRecordPage(this.data); | |||
class FeedbackRecordPage extends StatefulWidget { | |||
@override | |||
_FeedbackRecordPageState createState() => _FeedbackRecordPageState(); | |||
Widget build(BuildContext context) { | |||
return BlocProvider<FeedbackRecordBloc>( | |||
create: (_) => FeedbackRecordBloc(FeedbackRecordRepository(data))..add(FeedbackRecordInitEvent()), | |||
child: _FeedbackRecordPage(), | |||
); | |||
} | |||
} | |||
class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||
class _FeedbackRecordPage extends StatefulWidget { | |||
@override | |||
__FeedbackRecordPageState createState() => __FeedbackRecordPageState(); | |||
} | |||
class __FeedbackRecordPageState extends State<_FeedbackRecordPage> { | |||
RefreshController _controller; | |||
/// 点击详情 | |||
/// 刷新 | |||
void _refresh() { | |||
BlocProvider.of<FeedbackRecordBloc>(context).add(FeedbackRecordRefreshEvent()); | |||
} | |||
/// 加载更多 | |||
void _load() { | |||
BlocProvider.of<FeedbackRecordBloc>(context).add(FeedbackRecordLoadEvent()); | |||
} | |||
@override | |||
void initState() { | |||
_controller = RefreshController(); | |||
super.initState(); | |||
} | |||
@override | |||
void dispose() { | |||
_controller?.dispose(); | |||
super.dispose(); | |||
} | |||
@override | |||
Widget build(BuildContext context) { | |||
return BlocConsumer<FeedbackRecordBloc, FeedbackRecordState>( | |||
listener: (context, state) {}, | |||
buildWhen: (prev, current) { | |||
if (current is FeedbackRecordRefreshSuccessState) { | |||
_controller?.refreshCompleted(resetFooterState: true); | |||
return false; | |||
} | |||
if (current is FeedbackRecordRefreshErrorState) { | |||
_controller?.refreshFailed(); | |||
return false; | |||
} | |||
if (current is FeedbackRecordLoadSuccessState) { | |||
_controller?.loadComplete(); | |||
return false; | |||
} | |||
if (current is FeedbackRecordLoadErrorState) { | |||
_controller?.loadNoData(); | |||
return false; | |||
} | |||
return true; | |||
}, | |||
builder: (context, state) { | |||
/// 数据视图 | |||
if (state is FeedbackRecordLoadedState) { | |||
return _createDataWidget(state?.styleModel, state?.dataModel); | |||
} | |||
/// 初始化失败,空视图 | |||
if (state is FeedbackRecordInitErrorState) { | |||
return _createEmptyWidget(); | |||
} | |||
/// 加载中,骨架图 | |||
return _createSkeletonWidget(); | |||
}, | |||
); | |||
} | |||
/// 有数据 | |||
Widget _createDataWidget(FeedbackRecordStyleModel styleModel, FeedbackRecordDataModel dataModel) { | |||
int length = dataModel?.data?.length ?? 0; | |||
if(length == 0 ) return _createEmptyWidget(); | |||
return Scaffold( | |||
appBar: _createNav(styleModel), | |||
body: GestureDetector( | |||
onTap: () { | |||
FocusScope.of(context).requestFocus(FocusNode()); | |||
}, | |||
child: SafeArea( | |||
child: SmartRefresher( | |||
controller: _controller, | |||
enablePullUp: true, | |||
enablePullDown: true, | |||
onRefresh: _refresh, | |||
onLoading: _load, | |||
child: ListView.builder( | |||
itemCount: length, | |||
itemBuilder: (context, index) { | |||
return FeedbackRecordItem(styleModel, dataModel.data[index]); | |||
}), | |||
), | |||
), | |||
), | |||
); | |||
} | |||
/// 空数据 | |||
Widget _createEmptyWidget() { | |||
return Scaffold( | |||
appBar: _createNav(), | |||
appBar: _createNav(null), | |||
body: GestureDetector( | |||
onTap: () { | |||
FocusScope.of(context).requestFocus(FocusNode()); | |||
}, | |||
child: SafeArea( | |||
child: Center(child: EmptyWidget()), | |||
// child: ListView.builder( | |||
// itemCount: 10, | |||
// itemBuilder: (context, index) { | |||
// return FeedbackRecordItem(); | |||
// }), | |||
child: SmartRefresher( | |||
controller: _controller, | |||
enablePullDown: true, | |||
enablePullUp: false, | |||
onRefresh: _refresh, | |||
child: Center(child: EmptyWidget()), | |||
), | |||
), | |||
), | |||
); | |||
} | |||
// 导航栏 | |||
Widget _createNav() { | |||
/// 骨架图 | |||
Widget _createSkeletonWidget() { | |||
return Scaffold( | |||
appBar: _createNav(null), | |||
body: Container(), | |||
); | |||
} | |||
/// 导航栏 | |||
Widget _createNav(FeedbackRecordStyleModel styleModel) { | |||
return CupertinoNavigationBar( | |||
border: Border( | |||
bottom: BorderSide( | |||
@@ -38,7 +169,7 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||
style: BorderStyle.none, | |||
), | |||
), | |||
backgroundColor: Colors.white, | |||
backgroundColor: HexColor.fromHex(styleModel?.appBarBgColor ?? '#FFFFFF'), | |||
leading: Navigator.canPop(context) | |||
? GestureDetector( | |||
child: Container( | |||
@@ -56,10 +187,10 @@ class _FeedbackRecordPageState extends State<FeedbackRecordPage> { | |||
) | |||
: Container(), | |||
middle: Text( | |||
'反馈列表', | |||
styleModel?.appBarName ?? '反馈列表', | |||
style: TextStyle( | |||
fontSize: 15, | |||
color: Color(0xff333333), | |||
color: HexColor.fromHex(styleModel?.appBarNameColor ?? '#FF333333'), | |||
), | |||
), | |||
); | |||
@@ -1,4 +1,6 @@ | |||
class FeedbackModel { | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class FeedbackModel extends SkipModel{ | |||
String appBarName; | |||
String appBarNameColor; | |||
String appBarBgColor; | |||
@@ -73,6 +75,7 @@ class FeedbackModel { | |||
this.skipIdentifier}); | |||
FeedbackModel.fromJson(Map<String, dynamic> json) { | |||
super.fromJson(json); | |||
appBarName = json['app_bar_name']; | |||
appBarNameColor = json['app_bar_name_color']; | |||
appBarBgColor = json['app_bar_bg_color']; | |||
@@ -121,7 +124,7 @@ class FeedbackModel { | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
final Map<String, dynamic> data = super.toJson(); | |||
data['app_bar_name'] = this.appBarName; | |||
data['app_bar_name_color'] = this.appBarNameColor; | |||
data['app_bar_bg_color'] = this.appBarBgColor; | |||
@@ -0,0 +1,60 @@ | |||
/// 反馈列表数据 | |||
class FeedbackRecordDataModel { | |||
List<FeedbackRecordDataItemModel> data; | |||
FeedbackRecordDataModel({this.data}); | |||
FeedbackRecordDataModel.fromJson(Map<String, dynamic> json) { | |||
if (json['data'] != null) { | |||
data = new List<FeedbackRecordDataItemModel>(); | |||
json['data'].forEach((v) { | |||
data.add(new FeedbackRecordDataItemModel.fromJson(v)); | |||
}); | |||
} | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
if (this.data != null) { | |||
data['data'] = this.data.map((v) => v.toJson()).toList(); | |||
} | |||
return data; | |||
} | |||
} | |||
class FeedbackRecordDataItemModel { | |||
String id; | |||
String type; | |||
String typeText; | |||
String state; | |||
String title; | |||
String content; | |||
List<String> imageList; | |||
String createTime; | |||
FeedbackRecordDataItemModel({this.id, this.type, this.typeText, this.state, this.title, this.content, this.imageList, this.createTime}); | |||
FeedbackRecordDataItemModel.fromJson(Map<String, dynamic> json) { | |||
id = json['id']; | |||
type = json['type']; | |||
typeText = json['type_text']; | |||
state = json['state']; | |||
title = json['title']; | |||
content = json['content']; | |||
imageList = json['image_list'].cast<String>(); | |||
createTime = json['create_time']; | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['id'] = this.id; | |||
data['type'] = this.type; | |||
data['type_text'] = this.typeText; | |||
data['state'] = this.state; | |||
data['title'] = this.title; | |||
data['content'] = this.content; | |||
data['image_list'] = this.imageList; | |||
data['create_time'] = this.createTime; | |||
return data; | |||
} | |||
} |
@@ -0,0 +1,140 @@ | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
/// 反馈列表样式 | |||
class FeedbackRecordStyleModel extends SkipModel{ | |||
String appBarName; | |||
String appBarNameColor; | |||
String appBarBgColor; | |||
String bgColor; | |||
ItemStyle itemStyle; | |||
List<FeedbackTypes> feedbackTypes; | |||
List<StateImages> stateImages; | |||
String requiredLogin; | |||
String requiredTaobaoAuth; | |||
String skipIdentifier; | |||
FeedbackRecordStyleModel( | |||
{this.appBarName, | |||
this.appBarNameColor, | |||
this.appBarBgColor, | |||
this.bgColor, | |||
this.itemStyle, | |||
this.feedbackTypes, | |||
this.stateImages, | |||
this.requiredLogin, | |||
this.requiredTaobaoAuth, | |||
this.skipIdentifier}); | |||
FeedbackRecordStyleModel.fromJson(Map<String, dynamic> json) { | |||
super.fromJson(json); | |||
appBarName = json['app_bar_name']; | |||
appBarNameColor = json['app_bar_name_color']; | |||
appBarBgColor = json['app_bar_bg_color']; | |||
bgColor = json['bg_color']; | |||
itemStyle = json['item_style'] != null ? new ItemStyle.fromJson(json['item_style']) : null; | |||
if (json['feedback_types'] != null) { | |||
feedbackTypes = new List<FeedbackTypes>(); | |||
json['feedback_types'].forEach((v) { | |||
feedbackTypes.add(new FeedbackTypes.fromJson(v)); | |||
}); | |||
} | |||
if (json['state_images'] != null) { | |||
stateImages = new List<StateImages>(); | |||
json['state_images'].forEach((v) { | |||
stateImages.add(new StateImages.fromJson(v)); | |||
}); | |||
} | |||
requiredLogin = json['required_login']; | |||
requiredTaobaoAuth = json['required_taobao_auth']; | |||
skipIdentifier = json['skip_identifier']; | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = super.toJson(); | |||
data['app_bar_name'] = this.appBarName; | |||
data['app_bar_name_color'] = this.appBarNameColor; | |||
data['app_bar_bg_color'] = this.appBarBgColor; | |||
data['bg_color'] = this.bgColor; | |||
if (this.itemStyle != null) { | |||
data['item_style'] = this.itemStyle.toJson(); | |||
} | |||
if (this.feedbackTypes != null) { | |||
data['feedback_types'] = this.feedbackTypes.map((v) => v.toJson()).toList(); | |||
} | |||
if (this.stateImages != null) { | |||
data['state_images'] = this.stateImages.map((v) => v.toJson()).toList(); | |||
} | |||
data['required_login'] = this.requiredLogin; | |||
data['required_taobao_auth'] = this.requiredTaobaoAuth; | |||
data['skip_identifier'] = this.skipIdentifier; | |||
return data; | |||
} | |||
} | |||
class ItemStyle { | |||
String bgColor; | |||
String typeTextColor; | |||
String typeBgColor; | |||
String titleTextColor; | |||
String contentTextColor; | |||
String timeTextColor; | |||
ItemStyle({this.bgColor, this.typeTextColor, this.typeBgColor, this.titleTextColor, this.contentTextColor, this.timeTextColor}); | |||
ItemStyle.fromJson(Map<String, dynamic> json) { | |||
bgColor = json['bg_color']; | |||
typeTextColor = json['type_text_color']; | |||
typeBgColor = json['type_bg_color']; | |||
titleTextColor = json['title_text_color']; | |||
contentTextColor = json['content_text_color']; | |||
timeTextColor = json['time_text_color']; | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['bg_color'] = this.bgColor; | |||
data['type_text_color'] = this.typeTextColor; | |||
data['type_bg_color'] = this.typeBgColor; | |||
data['title_text_color'] = this.titleTextColor; | |||
data['content_text_color'] = this.contentTextColor; | |||
data['time_text_color'] = this.timeTextColor; | |||
return data; | |||
} | |||
} | |||
class FeedbackTypes { | |||
String typeId; | |||
String name; | |||
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; | |||
} | |||
} | |||
class StateImages { | |||
String stateId; | |||
String img; | |||
StateImages({this.stateId, this.img}); | |||
StateImages.fromJson(Map<String, dynamic> json) { | |||
stateId = json['state_id']; | |||
img = json['img']; | |||
} | |||
Map<String, dynamic> toJson() { | |||
final Map<String, dynamic> data = new Map<String, dynamic>(); | |||
data['state_id'] = this.stateId; | |||
data['img'] = this.img; | |||
return data; | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
import 'dart:io'; | |||
class FeedbackSaveModel { | |||
String type; | |||
String title; | |||
String content; | |||
List<File> files; | |||
FeedbackSaveModel({this.type, this.title, this.content, this.files}); | |||
} |
@@ -1,6 +1,14 @@ | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_data_model.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/model/feedback_record_style_model.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
class FeedbackRecordItem extends StatelessWidget { | |||
FeedbackRecordStyleModel styleModel; | |||
FeedbackRecordDataItemModel dataModel; | |||
FeedbackRecordItem(this.styleModel, this.dataModel); | |||
@override | |||
Widget build(BuildContext context) { | |||
return Container( | |||
@@ -8,7 +16,7 @@ class FeedbackRecordItem extends StatelessWidget { | |||
padding: EdgeInsets.all(15), | |||
width: double.infinity, | |||
decoration: BoxDecoration( | |||
color: Colors.white, | |||
color: HexColor.fromHex(styleModel?.itemStyle?.bgColor ?? '#FFFFFF'), | |||
borderRadius: BorderRadius.circular(7.5), | |||
), | |||
child: Row( | |||
@@ -31,40 +39,53 @@ class FeedbackRecordItem extends StatelessWidget { | |||
width: 60, | |||
height: 60, | |||
decoration: BoxDecoration( | |||
color: Colors.green, | |||
// color: Colors.green, | |||
borderRadius: BorderRadius.circular(30), | |||
), | |||
child: CachedNetworkImage( | |||
imageUrl: getStateImageUrl(), | |||
), | |||
) | |||
], | |||
), | |||
); | |||
} | |||
String getStateImageUrl(){ | |||
String result = ''; | |||
int length = styleModel?.stateImages?.length ?? 0; | |||
if(length > 0){ | |||
styleModel.stateImages.forEach((element) { | |||
if(element.stateId == dataModel.state){ | |||
result = element.img; | |||
} | |||
}); | |||
} | |||
return result; | |||
} | |||
Widget _createTitle() { | |||
List<InlineSpan> list = List(); | |||
list.add(WidgetSpan( | |||
child: Container( | |||
padding: EdgeInsets.only(left: 2, right: 2, top: 3, bottom: 3), | |||
padding: EdgeInsets.only(left: 4.5, right: 4.5, top: 3, bottom: 3), | |||
margin: EdgeInsets.only(right: 4), | |||
child: Text( | |||
'功能异常', | |||
dataModel?.typeText ?? '其它', | |||
style: TextStyle( | |||
fontSize: 9, | |||
height: 1, | |||
// color: HexColor.fromHex(style.providerNameColor), | |||
color: Colors.white, | |||
color: HexColor.fromHex(styleModel?.itemStyle?.typeTextColor ?? '#FFFFFF'), | |||
), | |||
), | |||
decoration: BoxDecoration( | |||
color: Colors.redAccent, borderRadius: BorderRadius.circular(2.5)), | |||
decoration: BoxDecoration(color: HexColor.fromHex(styleModel?.itemStyle?.typeBgColor ?? '#FF4242'), borderRadius: BorderRadius.circular(2.5)), | |||
), | |||
)); | |||
list.add(TextSpan( | |||
text: '关于关闭提现功能的反馈', | |||
style: TextStyle( | |||
fontSize: 14, color: Color(0xff333333), fontWeight: FontWeight.bold), | |||
text: dataModel?.title ?? '', | |||
style: TextStyle(fontSize: 14, color: HexColor.fromHex(styleModel?.itemStyle?.titleTextColor ?? '#333333'), fontWeight: FontWeight.bold), | |||
)); | |||
return RichText( | |||
maxLines: 2, | |||
@@ -76,32 +97,44 @@ class FeedbackRecordItem extends StatelessWidget { | |||
Widget _createDesc() { | |||
return Container( | |||
child: Text( | |||
'我今天想使用我的提现功能的时候,发现官方已经把这个功能给暂时关闭了,所以我很伤心,不开心不开心不开心,所以我很伤心,不开心不开心不开心', | |||
style: TextStyle(fontSize: 11, color: Color(0xff999999)), | |||
dataModel?.content ?? '', | |||
style: TextStyle(fontSize: 11, color: HexColor.fromHex(styleModel?.itemStyle?.contentTextColor ?? '#999999')), | |||
), | |||
); | |||
} | |||
Widget _createImage() { | |||
return Container( | |||
margin: EdgeInsets.only(top: 4, bottom: 4), | |||
child: Wrap( | |||
children: <Widget>[ | |||
List<Widget> images = []; | |||
int length = dataModel?.imageList?.length ?? 0; | |||
if (length > 0) { | |||
for (int i = 0; i < length; i++) { | |||
images.add( | |||
Container( | |||
width: 60, | |||
height: 60, | |||
color: Colors.redAccent, | |||
child: CachedNetworkImage( | |||
imageUrl: dataModel?.imageList[i] ?? '', | |||
), | |||
), | |||
], | |||
), | |||
); | |||
); | |||
} | |||
return Container( | |||
margin: EdgeInsets.only(top: 4, bottom: 4), | |||
child: Wrap( | |||
children: images, | |||
), | |||
); | |||
} else { | |||
return Container(); | |||
} | |||
} | |||
Widget _createTime() { | |||
return Container( | |||
child: Text( | |||
'2020-06-23 01:00:06', | |||
style: TextStyle(fontSize: 11, color: Color(0xffd8d8d8)), | |||
dataModel?.createTime ?? '', | |||
style: TextStyle(fontSize: 11, color: HexColor.fromHex(styleModel?.itemStyle?.timeTextColor ?? '#D8D8D8')), | |||
), | |||
); | |||
} | |||
@@ -22,7 +22,7 @@ class HotRankingPage extends StatefulWidget { | |||
_HotRankingPageState createState() => _HotRankingPageState(); | |||
} | |||
class _HotRankingPageState extends State<HotRankingPage> { | |||
class _HotRankingPageState extends State<HotRankingPage> with AutomaticKeepAliveClientMixin{ | |||
@override | |||
Widget build(BuildContext context) { | |||
print('hot_ranking_page build'); | |||
@@ -48,6 +48,10 @@ class _HotRankingPageState extends State<HotRankingPage> { | |||
), | |||
); | |||
} | |||
@override | |||
// TODO: implement wantKeepAlive | |||
bool get wantKeepAlive => true; | |||
} | |||
class _HotRankingPageContainer extends StatefulWidget { | |||
@@ -60,7 +64,7 @@ class _HotRankingPageContainer extends StatefulWidget { | |||
__HotRankingPageContainerState(); | |||
} | |||
class __HotRankingPageContainerState extends State<_HotRankingPageContainer> { | |||
class __HotRankingPageContainerState extends State<_HotRankingPageContainer> with AutomaticKeepAliveClientMixin{ | |||
HotRankingPageBloc _bloc; | |||
RefreshController _refreshController; | |||
String backgroundImage; | |||
@@ -136,6 +140,10 @@ class __HotRankingPageContainerState extends State<_HotRankingPageContainer> { | |||
} | |||
return list; | |||
} | |||
@override | |||
// TODO: implement wantKeepAlive | |||
bool get wantKeepAlive => true; | |||
} | |||
class _SilverAppBarDelegate extends SliverPersistentHeaderDelegate { | |||
@@ -1,5 +1,11 @@ | |||
import 'dart:io'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:zhiying_base_widget/pages/launch_page/launch_page.dart'; | |||
import 'package:zhiying_comm/util/log/let_log.dart'; | |||
import 'package:zhiying_comm/util/empty_util.dart'; | |||
import 'package:url_launcher/url_launcher.dart'; | |||
import 'package:webview_flutter/webview_flutter.dart'; | |||
class BaseWebview extends StatefulWidget { | |||
@@ -33,7 +39,18 @@ class _BaseWebviewState extends State<BaseWebview> { | |||
onWebViewCreated: (WebViewController webViewController) { | |||
_webViewController = webViewController; | |||
}, | |||
navigationDelegate: (NavigationRequest request) { | |||
navigationDelegate: (NavigationRequest request) async{ | |||
// 解决Android的拼多多webview 转发的问题 | |||
if(Platform.isAndroid){ | |||
String url = request?.url?.toString(); | |||
if(!EmptyUtil.isEmpty(url) && !url.startsWith('https://') && !url.startsWith('http://')){ | |||
Logger.log('navigation url = $url'); | |||
// if(await canLaunch(url)){ | |||
// await launch(url); | |||
// } | |||
return NavigationDecision.prevent; | |||
} | |||
} | |||
return NavigationDecision.navigate; | |||
}, | |||
onPageStarted: (String url) { | |||
@@ -363,10 +363,28 @@ class _WithdrawContainerState extends State<_WithdrawContainer> { | |||
} | |||
Widget _createSubmit(WithdrawModel model) { | |||
String value = model.cashOutDashbordItems[_currentIndex].value; | |||
// String value = model.cashOutDashbordItems[_currentIndex].value; | |||
// try { | |||
// if (num.tryParse(value) != null && | |||
// null != _bloc.withdrawDataModel && | |||
// num.tryParse(value) < | |||
// num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||
// _submitable = true; | |||
// } else { | |||
// _submitable = false; | |||
// } | |||
// } catch (e, s) { | |||
// print(e); | |||
// print(s); | |||
// } | |||
try { | |||
if (num.tryParse(value) != null && null != _bloc.withdrawDataModel && num.tryParse(value) < num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||
var currentWithdraw = num.tryParse(_controller.text); | |||
var finValue = num.tryParse(_bloc.withdrawDataModel.finValue); | |||
if (currentWithdraw != null && | |||
currentWithdraw != 0 && | |||
finValue != null && | |||
finValue != 0 && | |||
currentWithdraw <= finValue) { | |||
_submitable = true; | |||
} else { | |||
_submitable = false; | |||
@@ -434,18 +452,24 @@ class _WithdrawContainerState extends State<_WithdrawContainer> { | |||
); | |||
} | |||
///检查提现按钮是否可用 | |||
void _checkSubmit(String value) { | |||
try { | |||
if (num.tryParse(value) != null && | |||
num.tryParse(value) < num.tryParse(_bloc.withdrawDataModel.finValue)) { | |||
_submitable = true; | |||
} else { | |||
_submitable = false; | |||
} | |||
} catch (e, s) { | |||
print(e); | |||
print(s); | |||
} | |||
// try { | |||
// var currentValue = num.tryParse(value); | |||
// var finValue = num.tryParse(_bloc.withdrawDataModel.finValue); | |||
// | |||
// if (currentValue != null && | |||
// currentValue != 0 && | |||
// currentValue <= finValue && | |||
// finValue != 0) { | |||
// _submitable = true; | |||
// } else { | |||
// _submitable = false; | |||
// } | |||
// } catch (e, s) { | |||
// print(e); | |||
// print(s); | |||
// } | |||
setState(() {}); | |||
} | |||
} |
@@ -6,6 +6,7 @@ import 'package:sharesdk_plugin/sharesdk_register.dart'; | |||
import 'package:zhiying_base_widget/pages/about_us_page/about_us_page.dart'; | |||
import 'package:zhiying_base_widget/pages/bil_detail_page/bil_detail_page.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_page.dart'; | |||
import 'package:zhiying_base_widget/pages/feedback_page/feedback_record_page.dart'; | |||
import 'package:zhiying_base_widget/pages/goods_details_page/goods_details_page.dart'; | |||
import 'package:zhiying_base_widget/pages/home_page/home_page.dart'; | |||
import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page.dart'; | |||
@@ -58,6 +59,7 @@ import 'package:zhiying_base_widget/widgets/wallet_bil_detail/wallet_bil_detail. | |||
import 'package:zhiying_comm/util/defalut_widget_creater.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
import 'pages/custom_page/custom_page.dart'; | |||
import 'pages/favorites_page/favorites_page.dart'; | |||
import 'pages/message_notice_page/message_notice_page.dart'; | |||
import 'pages/privacy_settings_page/privacy_settings_page.dart'; | |||
@@ -139,6 +141,7 @@ class BaseWidgetRegister { | |||
PageFactory.regist( | |||
'search_result_item', (model) => SearchResultItemPage(model)); | |||
PageFactory.regist('pub.flutter.feedback', (model) => FeedbackPage(model)); | |||
PageFactory.regist('pub.flutter.feedback_list', (model) => FeedbackRecordPage(model)); | |||
PageFactory.regist( | |||
'pub.flutter.wechat_teacher', (model) => WechatTeacherPage()); | |||
PageFactory.regist('pub.flutter.cash_out', (model) => WithdrawPage(model)); | |||
@@ -199,7 +202,7 @@ class BaseWidgetRegister { | |||
'pub.flutter.my_wallet_detail', (model) => BilDetailPage(model)); | |||
/// 通用模块 | |||
PageFactory.regist('pub.flutter.custom', (model) => EmptyPage()); | |||
PageFactory.regist('pub.flutter.custom', (model) => CustomPage(model)); | |||
} | |||
// 注册控件 | |||
@@ -58,7 +58,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||
/// 点击领取 | |||
void _onJump(CounponModel model) async{ | |||
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model.toJson()); | |||
TurnChainUtil.openReceiveCoupon(context, _user, model.provider, model?.convertArgs?.toJson()); | |||
} | |||
@override | |||
@@ -73,7 +73,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||
}, | |||
builder: (context, state) { | |||
if (state is CounponLoadedState) { | |||
return _getMainWdiget(state.model); | |||
return _getMainWidget(state.model); | |||
} | |||
return CounponSkeleton(); | |||
}, | |||
@@ -81,7 +81,7 @@ class _CounponWidgetContainerState extends State<CounponWidgetContainer> { | |||
} | |||
/// 主视图 | |||
Widget _getMainWdiget(CounponModel model) { | |||
Widget _getMainWidget(CounponModel model) { | |||
return Visibility( | |||
visible: !EmptyUtil.isEmpty(model?.coupon_price), | |||
child: GestureDetector( | |||
@@ -97,18 +97,19 @@ class _GoodsDetailsImgWidgetContainerState | |||
return Column( | |||
children: model.image_detail_list.map((item) { | |||
return GestureDetector( | |||
onTap: () { | |||
if(item!=null){ | |||
PhotoPreview.showPhotoPreviewByimages( | |||
context, [item], | |||
currentIndex: 0); | |||
} | |||
}, | |||
child: CachedNetworkImage( | |||
imageUrl: item ?? '', | |||
fit: BoxFit.fitWidth, | |||
), | |||
); | |||
onTap: () { | |||
if (item != null) { | |||
PhotoPreview.showPhotoPreviewByimages(context, [item], | |||
currentIndex: 0, heroTagSuffix: "bottom"); | |||
} | |||
}, | |||
child: Hero( | |||
tag: item + "bottom", | |||
child: CachedNetworkImage( | |||
imageUrl: item ?? '', | |||
fit: BoxFit.fitWidth, | |||
), | |||
)); | |||
}).toList(), | |||
); | |||
} else { | |||
@@ -46,8 +46,9 @@ class _GoodsDetailsSlideBannerContainerState | |||
/// 子元素点击事件 | |||
void _itemOnClick(String model, List<String> images, int index) { | |||
print('点击了 $model'); | |||
if(images!=null){ | |||
PhotoPreview.showPhotoPreviewByimages(context, images, currentIndex: index); | |||
if (images != null) { | |||
PhotoPreview.showPhotoPreviewByimages(context, images, | |||
currentIndex: index, heroTagSuffix: "top"); | |||
} | |||
} | |||
@@ -108,7 +109,10 @@ class _GoodsDetailsSlideBannerContainerState | |||
String items = datas.image_list[index]; | |||
return Container( | |||
width: double.infinity, | |||
child: CachedNetworkImage(imageUrl: items ?? '', fit: BoxFit.cover), | |||
child: Hero( | |||
tag: items + "top", | |||
child: CachedNetworkImage( | |||
imageUrl: items ?? '', fit: BoxFit.cover)), | |||
); | |||
}, | |||
itemCount: datas?.image_list?.length ?? 0, | |||
@@ -12,25 +12,31 @@ class HotRankingGoods extends StatelessWidget { | |||
HotRankingListModel styleModel; | |||
int index; | |||
HotRankingGoods({Key key, this.good, this.styleModel, this.index}) : super(key: key); | |||
HotRankingGoods({Key key, this.good, this.styleModel, this.index}) | |||
: super(key: key); | |||
@override | |||
Widget build(BuildContext context) { | |||
var indexImage; | |||
if (styleModel.hotRankIconList != null && styleModel.hotRankIconList.length > 0 && styleModel.hotRankIconList.length - 1 >= index) { | |||
if (styleModel.hotRankIconList != null && | |||
styleModel.hotRankIconList.length > 0 && | |||
styleModel.hotRankIconList.length - 1 >= index) { | |||
indexImage = styleModel.hotRankIconList[index]; | |||
} | |||
Providers providers = getProvider(good.provider); | |||
return GestureDetector( | |||
onTap: () { | |||
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"), good?.toJson(), context); | |||
RouterUtil.route(SkipModel(skipIdentifier: "goods_details"), | |||
good?.toJson(), context); | |||
}, | |||
child: Stack( | |||
children: <Widget>[ | |||
Container( | |||
padding: EdgeInsets.all(15.w), | |||
margin: EdgeInsets.only(top: 8.w, bottom: 8.w, left: 25.w, right: 25.w), | |||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15.w)), | |||
margin: | |||
EdgeInsets.only(top: 8.w, bottom: 8.w, left: 25.w, right: 25.w), | |||
decoration: BoxDecoration( | |||
color: Colors.white, borderRadius: BorderRadius.circular(15.w)), | |||
child: Row( | |||
crossAxisAlignment: CrossAxisAlignment.start, | |||
children: <Widget>[ | |||
@@ -40,11 +46,15 @@ class HotRankingGoods extends StatelessWidget { | |||
height: 254.w, | |||
child: ClipRRect( | |||
borderRadius: BorderRadius.circular(6), | |||
child: CachedNetworkImage( | |||
imageUrl: good?.goodImage ?? '', | |||
child: Hero( | |||
tag: (good?.goodImage ?? "") + "top", | |||
child: CachedNetworkImage( | |||
imageUrl: good?.goodImage ?? '', | |||
), | |||
), | |||
), | |||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(6)), | |||
decoration: | |||
BoxDecoration(borderRadius: BorderRadius.circular(6)), | |||
), | |||
/// 商品图片右边视图 | |||
@@ -64,8 +74,12 @@ class HotRankingGoods extends StatelessWidget { | |||
WidgetSpan( | |||
alignment: ui.PlaceholderAlignment.middle, | |||
child: Container( | |||
padding: EdgeInsets.only(left: 4.w, right: 4.w, top: 1, bottom: 1), | |||
decoration: BoxDecoration(color: HexColor.fromHex(providers.providerBgColor), borderRadius: BorderRadius.circular(2.5)), | |||
padding: EdgeInsets.only( | |||
left: 4.w, right: 4.w, top: 1, bottom: 1), | |||
decoration: BoxDecoration( | |||
color: HexColor.fromHex( | |||
providers.providerBgColor), | |||
borderRadius: BorderRadius.circular(2.5)), | |||
child: Text( | |||
good.providerName ?? "", | |||
style: TextStyle( | |||
@@ -79,7 +93,12 @@ class HotRankingGoods extends StatelessWidget { | |||
child: SizedBox( | |||
width: 4.h, | |||
)), | |||
TextSpan(text: good.goodTitle, style: TextStyle(color: HexColor.fromHex(styleModel.titleColor ?? ""), fontSize: 30.sp)) | |||
TextSpan( | |||
text: good.goodTitle, | |||
style: TextStyle( | |||
color: HexColor.fromHex( | |||
styleModel.titleColor ?? ""), | |||
fontSize: 30.sp)) | |||
])), | |||
/// 优惠券 | |||
@@ -88,16 +107,32 @@ class HotRankingGoods extends StatelessWidget { | |||
good.coupon == "" | |||
? Container() | |||
: Container( | |||
margin: EdgeInsets.only(top: 4, bottom: 4, right: 15.w), | |||
margin: EdgeInsets.only( | |||
top: 4, bottom: 4, right: 15.w), | |||
decoration: BoxDecoration( | |||
borderRadius: BorderRadius.circular(2.5), | |||
color: HexColor.fromHex(styleModel.couponCommission.left.couponBgColor), | |||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.couponCommission.left.couponBgImg))), | |||
borderRadius: BorderRadius.circular(2.5), | |||
color: HexColor.fromHex(styleModel | |||
.couponCommission.left.couponBgColor), | |||
image: DecorationImage( | |||
image: CachedNetworkImageProvider( | |||
styleModel.couponCommission.left | |||
.couponBgImg))), | |||
child: Padding( | |||
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2), | |||
padding: const EdgeInsets.only( | |||
left: 8, right: 8, top: 2, bottom: 2), | |||
child: Text( | |||
(good.coupon ?? "") + (styleModel.couponCommission.left.couonText ?? ""), | |||
style: TextStyle(color: HexColor.fromHex(styleModel.couponCommission.left.couponFontColor), fontSize: 22.sp, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||
(good.coupon ?? "") + | |||
(styleModel.couponCommission.left | |||
.couonText ?? | |||
""), | |||
style: TextStyle( | |||
color: HexColor.fromHex(styleModel | |||
.couponCommission | |||
.left | |||
.couponFontColor), | |||
fontSize: 22.sp, | |||
fontFamily: 'Din', | |||
package: 'zhiying_base_widget'), | |||
), | |||
), | |||
), | |||
@@ -106,14 +141,33 @@ class HotRankingGoods extends StatelessWidget { | |||
: Container( | |||
margin: EdgeInsets.only(top: 4, bottom: 4), | |||
decoration: BoxDecoration( | |||
borderRadius: BorderRadius.circular(2.5), | |||
color: HexColor.fromHex(styleModel.couponCommission.right.commissionBgColor ?? ""), | |||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.couponCommission.right.commissionBgImg ?? ""))), | |||
borderRadius: BorderRadius.circular(2.5), | |||
color: HexColor.fromHex(styleModel | |||
.couponCommission | |||
.right | |||
.commissionBgColor ?? | |||
""), | |||
image: DecorationImage( | |||
image: CachedNetworkImageProvider( | |||
styleModel.couponCommission.right | |||
.commissionBgImg ?? | |||
""))), | |||
child: Padding( | |||
padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2), | |||
padding: const EdgeInsets.only( | |||
left: 8, right: 8, top: 2, bottom: 2), | |||
child: Text( | |||
(styleModel.couponCommission.right.commissionText ?? "") + (good.commission ?? ""), | |||
style: TextStyle(color: HexColor.fromHex(styleModel.couponCommission.right.commissionFontColor), fontSize: 22.sp,fontFamily: 'Din', package: 'zhiying_base_widget'), | |||
(styleModel.couponCommission.right | |||
.commissionText ?? | |||
"") + | |||
(good.commission ?? ""), | |||
style: TextStyle( | |||
color: HexColor.fromHex(styleModel | |||
.couponCommission | |||
.right | |||
.commissionFontColor), | |||
fontSize: 22.sp, | |||
fontFamily: 'Din', | |||
package: 'zhiying_base_widget'), | |||
), | |||
), | |||
), | |||
@@ -130,12 +184,21 @@ class HotRankingGoods extends StatelessWidget { | |||
padding: EdgeInsets.only(bottom: 6.sp), | |||
child: Text( | |||
"¥", | |||
style: TextStyle(color: HexColor.fromHex(styleModel.currentPriceColor ?? ""), fontSize: 20.sp), | |||
style: TextStyle( | |||
color: HexColor.fromHex( | |||
styleModel.currentPriceColor ?? ""), | |||
fontSize: 20.sp), | |||
), | |||
), | |||
Text( | |||
good.currentPrice ?? "", | |||
style: TextStyle(color: HexColor.fromHex(styleModel.currentPriceColor ?? ""), fontSize: 40.sp,fontWeight: FontWeight.bold ,fontFamily: 'Din', package: 'zhiying_base_widget'), | |||
style: TextStyle( | |||
color: HexColor.fromHex( | |||
styleModel.currentPriceColor ?? ""), | |||
fontSize: 40.sp, | |||
fontWeight: FontWeight.bold, | |||
fontFamily: 'Din', | |||
package: 'zhiying_base_widget'), | |||
), | |||
SizedBox( | |||
width: 6, | |||
@@ -144,7 +207,13 @@ class HotRankingGoods extends StatelessWidget { | |||
padding: EdgeInsets.only(bottom: 4.sp), | |||
child: Text( | |||
"¥" + good.marketPrice ?? "", | |||
style: TextStyle(color: HexColor.fromHex(styleModel.marketPriceColor ?? ""), fontSize: 22.sp, decoration: TextDecoration.lineThrough, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||
style: TextStyle( | |||
color: HexColor.fromHex( | |||
styleModel.marketPriceColor ?? ""), | |||
fontSize: 22.sp, | |||
decoration: TextDecoration.lineThrough, | |||
fontFamily: 'Din', | |||
package: 'zhiying_base_widget'), | |||
), | |||
), | |||
], | |||
@@ -167,11 +236,17 @@ class HotRankingGoods extends StatelessWidget { | |||
padding: EdgeInsets.only( | |||
left: 40.w, | |||
), | |||
margin: EdgeInsets.only(right: 20, left: 20.w), | |||
color: HexColor.fromHex(styleModel.hotRank.bgColor ?? ""), | |||
margin: | |||
EdgeInsets.only(right: 20, left: 20.w), | |||
color: HexColor.fromHex( | |||
styleModel.hotRank.bgColor ?? ""), | |||
child: Text( | |||
"热销" + good.inorderCount + "件", | |||
style: TextStyle(color: Colors.white, fontSize: 22.sp, fontFamily: 'Din', package: 'zhiying_base_widget'), | |||
style: TextStyle( | |||
color: Colors.white, | |||
fontSize: 22.sp, | |||
fontFamily: 'Din', | |||
package: 'zhiying_base_widget'), | |||
), | |||
)) | |||
], | |||
@@ -180,10 +255,12 @@ class HotRankingGoods extends StatelessWidget { | |||
width: 48.w, | |||
height: 48.w, | |||
child: CachedNetworkImage( | |||
imageUrl: styleModel?.hotRank?.hotSaleImg ?? "", | |||
imageUrl: | |||
styleModel?.hotRank?.hotSaleImg ?? "", | |||
width: 48.w, | |||
height: 48.w, | |||
placeholder: (context, _) => Container(color: Colors.yellow), | |||
placeholder: (context, _) => | |||
Container(color: Colors.yellow), | |||
fit: BoxFit.fill, | |||
), | |||
), | |||
@@ -193,8 +270,13 @@ class HotRankingGoods extends StatelessWidget { | |||
height: 48.h, | |||
width: 127.w, | |||
decoration: BoxDecoration( | |||
image: DecorationImage(image: CachedNetworkImageProvider(styleModel.hotRank.buyNowImg ?? ""), fit: BoxFit.fitWidth), | |||
borderRadius: BorderRadius.circular(20)), | |||
image: DecorationImage( | |||
image: CachedNetworkImageProvider( | |||
styleModel.hotRank.buyNowImg ?? | |||
""), | |||
fit: BoxFit.fitWidth), | |||
borderRadius: | |||
BorderRadius.circular(20)), | |||
margin: EdgeInsets.only(right: 0), | |||
)) | |||
], | |||
@@ -210,7 +292,9 @@ class HotRankingGoods extends StatelessWidget { | |||
Align( | |||
alignment: Alignment.topLeft, | |||
child: Container( | |||
decoration: BoxDecoration(image: DecorationImage(image: CachedNetworkImageProvider(indexImage ?? ""))), | |||
decoration: BoxDecoration( | |||
image: DecorationImage( | |||
image: CachedNetworkImageProvider(indexImage ?? ""))), | |||
margin: EdgeInsets.only(left: 40.w, top: 8.h), | |||
height: 60.w, | |||
width: 60.w, | |||
@@ -1,6 +1,11 @@ | |||
import 'dart:async'; | |||
import 'dart:convert'; | |||
import 'package:flutter/cupertino.dart'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||
import 'package:zhiying_base_widget/dialog/loading/loading.dart'; | |||
import 'package:zhiying_base_widget/dialog/loading/loading_dialog.dart'; | |||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | |||
import 'package:zhiying_comm/util/base_bloc.dart'; | |||
import 'package:zhiying_comm/zhiying_comm.dart'; | |||
@@ -25,7 +30,7 @@ class HotRankingListBloc extends BlocBase { | |||
_dataController = null; | |||
} | |||
void loadData(String typeId, int page,Function complete) { | |||
void loadData(String typeId, int page, Function complete) { | |||
if (isLoading) { | |||
complete(); | |||
return; | |||
@@ -35,16 +40,18 @@ class HotRankingListBloc extends BlocBase { | |||
NetUtil.request( | |||
'/api/v1/rec/taobao?type_id=' + typeId + '&page=' + page.toString(), | |||
method: NetMethod.GET, onSuccess: (data) { | |||
complete(); | |||
complete(); | |||
isLoading = false; | |||
_loadData(data); | |||
Loading.dismiss(); | |||
}, onError: (e) { | |||
complete(); | |||
Loading.dismiss(); | |||
complete(); | |||
isLoading = false; | |||
}); | |||
} | |||
void loadMoreData(String typeId,Function complete) { | |||
void loadMoreData(String typeId, Function complete) { | |||
if (isLoading) { | |||
complete(); | |||
return; | |||
@@ -2,6 +2,8 @@ import 'dart:convert'; | |||
import 'package:flutter/material.dart'; | |||
import 'package:pull_to_refresh/pull_to_refresh.dart'; | |||
import 'package:zhiying_base_widget/dialog/loading/loading.dart'; | |||
import 'package:zhiying_base_widget/dialog/loading/loading_dialog.dart'; | |||
import 'package:zhiying_base_widget/pages/hot_ranking_page/hot_ranking_page_bloc.dart'; | |||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_goods/hot_ranking_goods.dart'; | |||
import 'package:zhiying_base_widget/widgets/hot_ranking/hot_ranking_list/model/hot_ranking_list_data_model.dart'; | |||
@@ -23,7 +25,7 @@ class HotRankingList extends StatefulWidget { | |||
} | |||
class _HotRankingState extends State<HotRankingList> | |||
with TickerProviderStateMixin { | |||
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin { | |||
HotRankingListBloc _bloc; | |||
TabController _tabController; | |||
RefreshController _refreshController; | |||
@@ -33,6 +35,8 @@ class _HotRankingState extends State<HotRankingList> | |||
ScrollController _scrollcontroller; | |||
bool isFirstTime=true; | |||
@override | |||
void initState() { | |||
_bloc = HotRankingListBloc(); | |||
@@ -43,8 +47,14 @@ class _HotRankingState extends State<HotRankingList> | |||
if (_pageBloc != null) { | |||
_pageBloc.event.listen((event) { | |||
if (event.containsKey('type') && event['type'] == "loadData") { | |||
if(!isFirstTime){ | |||
Loading.show(context); | |||
} | |||
isFirstTime=false; | |||
_bloc.currentPage = 1; | |||
_bloc.loadData(event['type_id'], _bloc.currentPage, () {}); | |||
_scrollcontroller.animateTo(0, | |||
duration: Duration(milliseconds: 500), curve: Curves.bounceInOut); | |||
} | |||
}); | |||
} | |||
@@ -72,12 +82,7 @@ class _HotRankingState extends State<HotRankingList> | |||
return HotRankingSkeleton(); | |||
} else { | |||
goods = snapshot.data.good; | |||
if (_bloc.currentPage == 1) { | |||
Future.delayed(Duration(milliseconds: 100), () { | |||
_scrollcontroller.animateTo(0, | |||
duration: Duration(milliseconds: 100), curve: Curves.ease); | |||
}); | |||
} | |||
return SmartRefresher( | |||
controller: _refreshController, | |||
enablePullDown: true, | |||
@@ -121,4 +126,8 @@ class _HotRankingState extends State<HotRankingList> | |||
index: index, | |||
); | |||
} | |||
@override | |||
// TODO: implement wantKeepAlive | |||
bool get wantKeepAlive => true; | |||
} |