| @@ -217,6 +217,12 @@ | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.6" | |||
| }, | |||
| { | |||
| "name": "flutter_cupertino_date_picker", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/flutter_cupertino_date_picker-1.0.26+2", | |||
| "packageUri": "lib/", | |||
| "languageVersion": "1.19" | |||
| }, | |||
| { | |||
| "name": "flutter_native_image", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/flutter_native_image-0.0.5+2", | |||
| @@ -229,6 +235,12 @@ | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.0" | |||
| }, | |||
| { | |||
| "name": "flutter_plugin_android_lifecycle", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/flutter_plugin_android_lifecycle-1.0.9", | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.1" | |||
| }, | |||
| { | |||
| "name": "flutter_screenutil", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/flutter_screenutil-1.1.0", | |||
| @@ -301,6 +313,24 @@ | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.0" | |||
| }, | |||
| { | |||
| "name": "image_cropper", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/git/Image_Cropper-e32f2264f86a27a2f5d7a7a5e26c6154eaf5798e/", | |||
| "packageUri": "lib/", | |||
| "languageVersion": "1.20" | |||
| }, | |||
| { | |||
| "name": "image_picker", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/image_picker-0.6.7+7", | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.1" | |||
| }, | |||
| { | |||
| "name": "image_picker_platform_interface", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/image_picker_platform_interface-1.1.0", | |||
| "packageUri": "lib/", | |||
| "languageVersion": "2.5" | |||
| }, | |||
| { | |||
| "name": "intl", | |||
| "rootUri": "file:///Users/fnuser/.pub-cache/hosted/pub.flutter-io.cn/intl-0.16.1", | |||
| @@ -680,7 +710,7 @@ | |||
| "languageVersion": "2.1" | |||
| } | |||
| ], | |||
| "generated": "2020-09-15T07:31:12.840893Z", | |||
| "generated": "2020-09-16T07:59:23.044545Z", | |||
| "generator": "pub", | |||
| "generatorVersion": "2.7.2" | |||
| } | |||
| @@ -4,11 +4,18 @@ PODS: | |||
| - Flutter (1.0.0) | |||
| - flutter_native_image (0.0.1): | |||
| - Flutter | |||
| - flutter_plugin_android_lifecycle (0.0.1): | |||
| - Flutter | |||
| - fluttertoast (0.0.2): | |||
| - Flutter | |||
| - FMDB (2.7.5): | |||
| - FMDB/standard (= 2.7.5) | |||
| - FMDB/standard (2.7.5) | |||
| - image_cropper (0.0.2): | |||
| - Flutter | |||
| - TOCropViewController (~> 2.5.2) | |||
| - image_picker (0.0.1): | |||
| - Flutter | |||
| - package_info (0.0.1): | |||
| - Flutter | |||
| - path_provider (0.0.1): | |||
| @@ -28,6 +35,7 @@ PODS: | |||
| - sqflite (0.0.1): | |||
| - Flutter | |||
| - FMDB (~> 2.7.2) | |||
| - TOCropViewController (2.5.3) | |||
| - zhiying_base_widget (0.0.1): | |||
| - Flutter | |||
| - zhiying_comm (0.0.1): | |||
| @@ -37,7 +45,10 @@ DEPENDENCIES: | |||
| - device_info (from `.symlinks/plugins/device_info/ios`) | |||
| - Flutter (from `Flutter`) | |||
| - flutter_native_image (from `.symlinks/plugins/flutter_native_image/ios`) | |||
| - flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`) | |||
| - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) | |||
| - image_cropper (from `.symlinks/plugins/image_cropper/ios`) | |||
| - image_picker (from `.symlinks/plugins/image_picker/ios`) | |||
| - package_info (from `.symlinks/plugins/package_info/ios`) | |||
| - path_provider (from `.symlinks/plugins/path_provider/ios`) | |||
| - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) | |||
| @@ -53,6 +64,7 @@ DEPENDENCIES: | |||
| SPEC REPOS: | |||
| trunk: | |||
| - FMDB | |||
| - TOCropViewController | |||
| EXTERNAL SOURCES: | |||
| device_info: | |||
| @@ -61,8 +73,14 @@ EXTERNAL SOURCES: | |||
| :path: Flutter | |||
| flutter_native_image: | |||
| :path: ".symlinks/plugins/flutter_native_image/ios" | |||
| flutter_plugin_android_lifecycle: | |||
| :path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios" | |||
| fluttertoast: | |||
| :path: ".symlinks/plugins/fluttertoast/ios" | |||
| image_cropper: | |||
| :path: ".symlinks/plugins/image_cropper/ios" | |||
| image_picker: | |||
| :path: ".symlinks/plugins/image_picker/ios" | |||
| package_info: | |||
| :path: ".symlinks/plugins/package_info/ios" | |||
| path_provider: | |||
| @@ -90,8 +108,11 @@ SPEC CHECKSUMS: | |||
| device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 | |||
| Flutter: 0e3d915762c693b495b44d77113d4970485de6ec | |||
| flutter_native_image: 9c0b7451838484458e5b0fae007b86a4c2d4bdfe | |||
| flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 | |||
| fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b | |||
| FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a | |||
| image_cropper: 3c16d7651730ffe85897f5a1c4e2547e6b54989a | |||
| image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 | |||
| package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 | |||
| path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c | |||
| path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 | |||
| @@ -101,6 +122,7 @@ SPEC CHECKSUMS: | |||
| shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 | |||
| shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 | |||
| sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 | |||
| TOCropViewController: 20a14b6a7a098308bf369e7c8d700dc983a974e6 | |||
| zhiying_base_widget: 00868c0d2723a3a425c18b27204fbc67e3f7e59d | |||
| zhiying_comm: 0daef4a480f4f4dbea3e11b615f3264aafea924b | |||
| @@ -162,6 +162,7 @@ | |||
| 9705A1C41CF9048500538489 /* Embed Frameworks */, | |||
| 3B06AD1E1E4923F5004D2608 /* Thin Binary */, | |||
| 3DD5E1C6552F1CEFD4C31B18 /* [CP] Embed Pods Frameworks */, | |||
| E6B4F9F34A4509DF5D9BF2D8 /* [CP] Copy Pods Resources */, | |||
| ); | |||
| buildRules = ( | |||
| ); | |||
| @@ -286,6 +287,21 @@ | |||
| shellPath = /bin/sh; | |||
| shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; | |||
| }; | |||
| E6B4F9F34A4509DF5D9BF2D8 /* [CP] Copy Pods Resources */ = { | |||
| isa = PBXShellScriptBuildPhase; | |||
| buildActionMask = 2147483647; | |||
| files = ( | |||
| ); | |||
| inputPaths = ( | |||
| ); | |||
| name = "[CP] Copy Pods Resources"; | |||
| outputPaths = ( | |||
| ); | |||
| runOnlyForDeploymentPostprocessing = 0; | |||
| shellPath = /bin/sh; | |||
| shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; | |||
| showEnvVarsInLog = 0; | |||
| }; | |||
| /* End PBXShellScriptBuildPhase section */ | |||
| /* Begin PBXSourcesBuildPhase section */ | |||
| @@ -386,6 +402,7 @@ | |||
| "$(PROJECT_DIR)/Flutter", | |||
| ); | |||
| INFOPLIST_FILE = Runner/Info.plist; | |||
| IPHONEOS_DEPLOYMENT_TARGET = 8.0; | |||
| LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | |||
| LIBRARY_SEARCH_PATHS = ( | |||
| "$(inherited)", | |||
| @@ -519,6 +536,7 @@ | |||
| "$(PROJECT_DIR)/Flutter", | |||
| ); | |||
| INFOPLIST_FILE = Runner/Info.plist; | |||
| IPHONEOS_DEPLOYMENT_TARGET = 8.0; | |||
| LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | |||
| LIBRARY_SEARCH_PATHS = ( | |||
| "$(inherited)", | |||
| @@ -545,6 +563,7 @@ | |||
| "$(PROJECT_DIR)/Flutter", | |||
| ); | |||
| INFOPLIST_FILE = Runner/Info.plist; | |||
| IPHONEOS_DEPLOYMENT_TARGET = 8.0; | |||
| LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; | |||
| LIBRARY_SEARCH_PATHS = ( | |||
| "$(inherited)", | |||
| @@ -41,5 +41,19 @@ | |||
| </array> | |||
| <key>UIViewControllerBasedStatusBarAppearance</key> | |||
| <false/> | |||
| <key>NSCameraUsageDescription</key> | |||
| <string>获取相机权限更换头像或者扫码</string> | |||
| <key>NSContactsUsageDescription</key> | |||
| <string>获取访问通信录权限添加联系人信息</string> | |||
| <key>NSLocationAlwaysUsageDescription</key> | |||
| <string>获取定位权限用于搜索附近的网点和查找附近的油站信息</string> | |||
| <key>NSLocationWhenInUseUsageDescription</key> | |||
| <string>获取定位权限用于搜索附近的网点和查找附近的油站信息</string> | |||
| <key>NSMicrophoneUsageDescription</key> | |||
| <string>获取访问麦克风权限录制语音或视频</string> | |||
| <key>NSPhotoLibraryAddUsageDescription</key> | |||
| <string>获取访问相册权限更换头像</string> | |||
| <key>NSPhotoLibraryUsageDescription</key> | |||
| <string>获取访问相册权限更换头像</string> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,83 @@ | |||
| import 'dart:async'; | |||
| import 'dart:io'; | |||
| import 'package:fluttertoast/fluttertoast.dart'; | |||
| import 'package:path/path.dart'; | |||
| import 'package:zhiying_base_widget/pages/mine_detail_page/models/mine_detail_model.dart'; | |||
| import 'package:zhiying_comm/util/base_bloc.dart'; | |||
| import 'package:zhiying_comm/zhiying_comm.dart'; | |||
| class MineDetailBloc extends BlocBase { | |||
| MineDetailModel _user; | |||
| StreamController<MineDetailModel> _userController = | |||
| StreamController<MineDetailModel>(); | |||
| Stream<MineDetailModel> get outData => _userController.stream; | |||
| @override | |||
| void dispose() { | |||
| _userController.close(); | |||
| _userController = null; | |||
| } | |||
| void loadData() { | |||
| NetUtil.request('/api/v1/user/info', method: NetMethod.GET, | |||
| onCache: (data) { | |||
| if (_user == null) _loadData(data); | |||
| }, onSuccess: (data) { | |||
| _loadData(data); | |||
| }); | |||
| } | |||
| void _loadData(dynamic data) { | |||
| _user = MineDetailModel.fromJson(Map<String, dynamic>.from(data)); | |||
| _userController.add(_user); | |||
| } | |||
| /* 更新用户信息 | |||
| nickname 昵称 | |||
| gender 性别(1女2男3未知) | |||
| birthday 生日(时间戳) | |||
| * */ | |||
| void updateUser({String nickname, String gender, String birthday}) { | |||
| Map<String, dynamic> params = Map(); | |||
| if (nickname != null && nickname != '') { | |||
| params['nickname'] = nickname; | |||
| } | |||
| if (gender != null && gender != '') { | |||
| params['gender'] = gender; | |||
| } | |||
| if (birthday != null && birthday != '') { | |||
| params['birthday'] = birthday; | |||
| } | |||
| NetUtil.request('/api/v1/user/info', | |||
| method: NetMethod.POST, | |||
| params: params, | |||
| onCache: (data) {}, onSuccess: (data) { | |||
| Fluttertoast.showToast(msg: '修改成功'); | |||
| loadData(); | |||
| }); | |||
| } | |||
| void uploadAvatar(File file) async { | |||
| List<int> originBytes = await file.readAsBytes(); | |||
| print('原图大小:' + originBytes.length.toString() + 'byte'); | |||
| print('原图大小:' + basename(file.path)); | |||
| Map<String, dynamic> params = Map(); | |||
| params['dir'] = 'avatar'; | |||
| params['file_size'] = originBytes.length; | |||
| params['file_name'] = basename(file.path); | |||
| NetUtil.request('/api/v1/file/upload', | |||
| method: NetMethod.PUT, | |||
| params: params, | |||
| onCache: (data) {}, onSuccess: (data) { | |||
| String method = data['method']; | |||
| String host = data['host']; | |||
| String key = data['key']; | |||
| String token = data['token']; | |||
| }); | |||
| } | |||
| } | |||
| @@ -0,0 +1,347 @@ | |||
| import 'dart:io'; | |||
| import 'package:cached_network_image/cached_network_image.dart'; | |||
| import 'package:flutter/cupertino.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:fluttertoast/fluttertoast.dart'; | |||
| import 'package:image_cropper/image_cropper.dart'; | |||
| import 'package:image_picker/image_picker.dart'; | |||
| import 'package:intl/intl.dart'; | |||
| import 'package:zhiying_base_widget/pages/mine_detail_page/mine_detail_bloc.dart'; | |||
| import 'package:zhiying_base_widget/pages/mine_detail_page/models/mine_detail_model.dart'; | |||
| import 'package:zhiying_base_widget/widgets/others/action_date_alert/action_date_alert.dart'; | |||
| import 'package:zhiying_base_widget/widgets/others/action_list_alert/action_list_alert.dart'; | |||
| import 'package:zhiying_base_widget/widgets/others/action_selected_alert/action_selected_alert.dart'; | |||
| import 'package:zhiying_comm/util/base_bloc.dart'; | |||
| import 'package:zhiying_comm/zhiying_comm.dart'; | |||
| class MineDetailPage extends StatefulWidget { | |||
| @override | |||
| _MineDetailPageState createState() => _MineDetailPageState(); | |||
| } | |||
| class _MineDetailPageState extends State<MineDetailPage> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| backgroundColor: Color(0xfff9f9f9), | |||
| appBar: _createNav(), | |||
| body: SafeArea( | |||
| child: BlocProvider<MineDetailBloc>( | |||
| bloc: MineDetailBloc(), | |||
| child: _MineDetailContainer(), | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| // 导航栏 | |||
| Widget _createNav() { | |||
| return CupertinoNavigationBar( | |||
| border: Border( | |||
| bottom: BorderSide( | |||
| width: 0.0, // One physical pixel. | |||
| style: BorderStyle.none, | |||
| ), | |||
| ), | |||
| backgroundColor: Colors.white, | |||
| leading: Navigator.canPop(context) | |||
| ? GestureDetector( | |||
| child: Container( | |||
| padding: EdgeInsets.zero, | |||
| child: Icon( | |||
| Icons.arrow_back_ios, | |||
| size: 20, | |||
| ), | |||
| ), | |||
| onTap: () { | |||
| if (Navigator.canPop(context)) { | |||
| Navigator.pop(context); | |||
| } | |||
| }, | |||
| ) | |||
| : Container(), | |||
| middle: Text( | |||
| '个人信息', | |||
| style: TextStyle( | |||
| fontSize: 15, | |||
| color: Color(0xff333333), | |||
| ), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||
| class _MineDetailContainer extends StatefulWidget { | |||
| @override | |||
| _MineDetailContainerState createState() => _MineDetailContainerState(); | |||
| } | |||
| class _MineDetailContainerState extends State<_MineDetailContainer> { | |||
| MineDetailBloc _bloc; | |||
| TextEditingController _nickController = TextEditingController(); | |||
| @override | |||
| void initState() { | |||
| _bloc = BlocProvider.of<MineDetailBloc>(context); | |||
| _bloc.loadData(); | |||
| super.initState(); | |||
| } | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return StreamBuilder<MineDetailModel>( | |||
| stream: _bloc.outData, | |||
| builder: (BuildContext context, AsyncSnapshot snapshot) { | |||
| MineDetailModel user = snapshot.data; | |||
| int birthday = int.tryParse(user?.birthday) ?? 0; | |||
| int registTime = int.tryParse(user?.registerTime) ?? 0; | |||
| _nickController.text = user?.nickname ?? ''; | |||
| return SingleChildScrollView( | |||
| child: Column( | |||
| children: <Widget>[ | |||
| _creteHeader(user, onTap: () { | |||
| _selectImage(); | |||
| }), | |||
| _createInput('昵称', _nickController, onTap: () {}), | |||
| _createLine(), | |||
| _createItem('性别', user?.gender, onTap: () { | |||
| _selectSex(); | |||
| }), | |||
| _createLine(), | |||
| _createItem( | |||
| '出生日期', | |||
| birthday > 0 | |||
| ? DateFormat('yyyy-MM-dd').format( | |||
| DateTime.fromMillisecondsSinceEpoch( | |||
| birthday * 1000)) | |||
| : user?.birthday ?? '', onTap: () { | |||
| _selectBrithday(); | |||
| }), | |||
| _createLine(), | |||
| _createItem( | |||
| '注册时间', | |||
| registTime > 0 | |||
| ? DateFormat('yyyy-MM-dd').format( | |||
| DateTime.fromMillisecondsSinceEpoch( | |||
| registTime * 1000)) | |||
| : user?.registerTime ?? ''), | |||
| ], | |||
| ), | |||
| ); | |||
| }); | |||
| } | |||
| // 头像 | |||
| Widget _creteHeader(MineDetailModel user, {VoidCallback onTap}) { | |||
| return GestureDetector( | |||
| child: Container( | |||
| height: 140, | |||
| width: double.infinity, | |||
| margin: EdgeInsets.only(top: 5), | |||
| color: Colors.white, | |||
| child: Column( | |||
| children: <Widget>[ | |||
| Container( | |||
| width: 80, | |||
| height: 80, | |||
| margin: EdgeInsets.only(top: 15), | |||
| decoration: BoxDecoration( | |||
| borderRadius: BorderRadius.circular(40), | |||
| color: Colors.black12), | |||
| child: ClipRRect( | |||
| borderRadius: BorderRadius.circular(40), | |||
| child: CachedNetworkImage( | |||
| imageUrl: user?.avatar ?? '', | |||
| fit: BoxFit.cover, | |||
| ), | |||
| ), | |||
| ), | |||
| Padding( | |||
| padding: const EdgeInsets.all(6.0), | |||
| child: Text( | |||
| user == null ? '' : '点击更换头像', | |||
| style: TextStyle(fontSize: 11, color: Color(0xff999999)), | |||
| ), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| onTap: onTap, | |||
| ); | |||
| } | |||
| Widget _createItem(String title, String desc, {VoidCallback onTap}) { | |||
| return GestureDetector( | |||
| child: Container( | |||
| padding: EdgeInsets.only(left: 12.5, right: 12.5), | |||
| height: 48, | |||
| color: Colors.white, | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Text( | |||
| title ?? '', | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Color(0xff333333), | |||
| fontWeight: FontWeight.bold), | |||
| ), | |||
| ), | |||
| Text( | |||
| desc ?? '', | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Color(0xff999999), | |||
| ), | |||
| ), | |||
| onTap == null | |||
| ? Container() | |||
| : Icon( | |||
| Icons.arrow_forward_ios, | |||
| size: 12, | |||
| color: Color(0xff999999), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| onTap: onTap, | |||
| ); | |||
| } | |||
| Widget _createInput(String title, TextEditingController controller, | |||
| {VoidCallback onTap}) { | |||
| return GestureDetector( | |||
| child: Container( | |||
| padding: EdgeInsets.only(left: 12.5, right: 12.5), | |||
| height: 48, | |||
| color: Colors.white, | |||
| child: Row( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Text( | |||
| title ?? '', | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Color(0xff333333), | |||
| fontWeight: FontWeight.bold), | |||
| ), | |||
| ), | |||
| Expanded( | |||
| child: CupertinoTextField( | |||
| decoration: BoxDecoration(color: Colors.transparent), | |||
| textInputAction: TextInputAction.done, | |||
| controller: controller, | |||
| textAlign: TextAlign.right, | |||
| placeholder: '输入昵称', | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Color(0xff999999), | |||
| ), | |||
| onSubmitted: (value) { | |||
| if (value == null || value == '') { | |||
| Fluttertoast.showToast(msg: '昵称不为空'); | |||
| return; | |||
| } | |||
| _bloc.updateUser(nickname: value); | |||
| }, | |||
| ), | |||
| ), | |||
| onTap == null | |||
| ? Container() | |||
| : Icon( | |||
| Icons.arrow_forward_ios, | |||
| size: 12, | |||
| color: Color(0xff999999), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| onTap: onTap, | |||
| ); | |||
| } | |||
| Widget _createLine() { | |||
| return Container( | |||
| width: double.infinity, | |||
| height: 0.5, | |||
| margin: EdgeInsets.only(left: 12.5, right: 12.5), | |||
| color: Color(0xfff4f4f4), | |||
| ); | |||
| } | |||
| void _selectImage() async { | |||
| 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; | |||
| File cropperFile = await ImageCropper.cropImage( | |||
| sourcePath: file.path, | |||
| aspectRatioPresets: [ | |||
| CropAspectRatioPreset.square, | |||
| ], | |||
| androidUiSettings: AndroidUiSettings( | |||
| toolbarTitle: '图片剪裁', | |||
| toolbarColor: HexColor.fromHex('#E52425'), | |||
| toolbarWidgetColor: Colors.white, | |||
| initAspectRatio: CropAspectRatioPreset.original, | |||
| lockAspectRatio: true), | |||
| iosUiSettings: IOSUiSettings( | |||
| minimumAspectRatio: 1.0, aspectRatioLockEnabled: true)); | |||
| File resultFile = await EncodeUtil.compressImage(cropperFile, 800); | |||
| _bloc.uploadAvatar(resultFile); | |||
| } | |||
| } | |||
| // 选择性别 | |||
| void _selectSex() async { | |||
| int index = await showModalBottomSheet( | |||
| context: context, | |||
| builder: (context) { | |||
| return ActionListAlert( | |||
| title: '选择性别', | |||
| actions: ['女', '男'], | |||
| ); | |||
| }, | |||
| isScrollControlled: false, | |||
| backgroundColor: Colors.transparent); | |||
| if (index != null) { | |||
| print(index); | |||
| _bloc.updateUser(gender: index == 0 ? '1' : '2'); | |||
| } | |||
| } | |||
| void _selectBrithday() async { | |||
| DateTime dateTime = await showModalBottomSheet( | |||
| context: context, | |||
| builder: (context) { | |||
| return ActionDateAlert( | |||
| title: '选择出生日期', | |||
| ); | |||
| }, | |||
| isScrollControlled: false, | |||
| backgroundColor: Colors.transparent); | |||
| if (dateTime != null) { | |||
| String timeStamp = | |||
| (dateTime.millisecondsSinceEpoch / 1000).ceil().toString(); | |||
| _bloc.updateUser(birthday: timeStamp); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| import 'package:json_annotation/json_annotation.dart'; | |||
| part 'mine_detail_model.g.dart'; | |||
| @JsonSerializable() | |||
| class MineDetailModel extends Object { | |||
| @JsonKey(name: 'avatar') | |||
| String avatar; | |||
| @JsonKey(name: 'nickname') | |||
| String nickname; | |||
| @JsonKey(name: 'gender') | |||
| String gender; | |||
| @JsonKey(name: 'birthday') | |||
| String birthday; | |||
| @JsonKey(name: 'register_time') | |||
| String registerTime; | |||
| MineDetailModel( | |||
| this.avatar, | |||
| this.nickname, | |||
| this.gender, | |||
| this.birthday, | |||
| this.registerTime, | |||
| ); | |||
| factory MineDetailModel.fromJson(Map<String, dynamic> srcJson) => | |||
| _$MineDetailModelFromJson(srcJson); | |||
| Map<String, dynamic> toJson() => _$MineDetailModelToJson(this); | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| // GENERATED CODE - DO NOT MODIFY BY HAND | |||
| part of 'mine_detail_model.dart'; | |||
| // ************************************************************************** | |||
| // JsonSerializableGenerator | |||
| // ************************************************************************** | |||
| MineDetailModel _$MineDetailModelFromJson(Map<String, dynamic> json) { | |||
| return MineDetailModel( | |||
| json['avatar'] as String, | |||
| json['nickname'] as String, | |||
| json['gender'] as String, | |||
| json['birthday'] as String, | |||
| json['register_time'] as String, | |||
| ); | |||
| } | |||
| Map<String, dynamic> _$MineDetailModelToJson(MineDetailModel instance) => | |||
| <String, dynamic>{ | |||
| 'avatar': instance.avatar, | |||
| 'nickname': instance.nickname, | |||
| 'gender': instance.gender, | |||
| 'birthday': instance.birthday, | |||
| 'register_time': instance.registerTime, | |||
| }; | |||
| @@ -1,5 +1,6 @@ | |||
| import 'package:zhiying_base_widget/pages/home_page/home_page.dart'; | |||
| import 'package:zhiying_base_widget/pages/main_page/main_page.dart'; | |||
| import 'package:zhiying_base_widget/pages/mine_detail_page/mine_detail_page.dart'; | |||
| import 'package:zhiying_base_widget/pages/wallet_page/wallet_page.dart'; | |||
| import 'package:zhiying_base_widget/widgets/home/home_banner/home_banner_creater.dart'; | |||
| import 'package:zhiying_base_widget/widgets/home/home_banner/home_banner_widget.dart'; | |||
| @@ -35,6 +36,9 @@ class BaseWidgetRegister { | |||
| // PageFactory.regist('login_quick', (model) => LoginQuickPage(model)); | |||
| // PageFactory.regist('login_account', (model) => LoginAccountPage(model)); | |||
| // PageFactory.regist('login_invite', (model) => LoginInvitePage()); | |||
| PageFactory.regist( | |||
| 'pub.flutter.profile_settings', (model) => MineDetailPage()); | |||
| } | |||
| // 注册控件 | |||
| @@ -12,11 +12,10 @@ class MineDataWidget extends StatelessWidget { | |||
| Map<String, dynamic> _json; | |||
| MineDataModel _style; | |||
| MineDataWidget( | |||
| this.profile, | |||
| this.data, { | |||
| Key key, | |||
| }) : super(key: key) { | |||
| MineDataWidget(this.profile, | |||
| this.data, { | |||
| Key key, | |||
| }) : super(key: key) { | |||
| String d = data['data']; | |||
| _json = convert.jsonDecode(d); | |||
| _style = MineDataModel.fromJson(Map<String, dynamic>.from(_json)); | |||
| @@ -87,7 +86,11 @@ class MineDataWidget extends StatelessWidget { | |||
| fontWeight: FontWeight.w800, | |||
| color: HexColor.fromHex( | |||
| _style.accumulatedEarningsNameColor), | |||
| fontFamily: 'Din', | |||
| fontFamily: 'Din-Bold' | |||
| '' | |||
| '' | |||
| '' | |||
| '', | |||
| package: 'zhiying_base_widget', | |||
| ), | |||
| ), | |||
| @@ -218,7 +221,7 @@ class MineDataWidget extends StatelessWidget { | |||
| style: TextStyle( | |||
| fontSize: 18, | |||
| color: HexColor.fromHex(_style.gridViewValueColor), | |||
| fontFamily: 'Din', | |||
| fontFamily: 'Din-Bold', | |||
| package: 'zhiying_base_widget'), | |||
| ), | |||
| ), | |||
| @@ -250,7 +253,7 @@ class MineDataWidget extends StatelessWidget { | |||
| style: TextStyle( | |||
| fontSize: 12, | |||
| color: HexColor.fromHex(_style.gridViewValueColor), | |||
| fontFamily: 'Din', | |||
| fontFamily: 'Din-Bold', | |||
| package: 'zhiying_base_widget'), | |||
| ), | |||
| ), | |||
| @@ -28,6 +28,16 @@ class _MineHeaderState extends State<MineHeader> { | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| // return Consumer<UserInfoNotifier>(builder: (context, user, child) { | |||
| // print('user ${user.toString()}'); | |||
| // if (user == null) { | |||
| // return MineStaticContainer(widget.data); | |||
| // } | |||
| // return BlocProvider<MineHeaderBloc>( | |||
| // bloc: MineHeaderBloc(), | |||
| // child: MineHeaderContainer(widget.data), | |||
| // ); | |||
| // }); | |||
| if (_isSketelon) { | |||
| Provider.of<UserInfoNotifier>(context).getUserInfoModel().then((user) { | |||
| setState(() { | |||
| @@ -0,0 +1,107 @@ | |||
| import 'package:flutter/cupertino.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:flutter_cupertino_date_picker/flutter_cupertino_date_picker.dart'; | |||
| import 'package:zhiying_comm/zhiying_comm.dart'; | |||
| class ActionDateAlert extends StatefulWidget { | |||
| final String title; | |||
| final TextStyle normalStyle; | |||
| final TextStyle selectedStyle; | |||
| const ActionDateAlert({ | |||
| Key key, | |||
| this.title, | |||
| this.normalStyle, | |||
| this.selectedStyle, | |||
| }) : super(key: key); | |||
| @override | |||
| State<StatefulWidget> createState() => _ActionDateAlert(); | |||
| } | |||
| class _ActionDateAlert extends State<ActionDateAlert> { | |||
| DateTime _dateTime = DateTime.now(); | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| backgroundColor: Colors.transparent, | |||
| body: GestureDetector( | |||
| child: Column( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Container(), | |||
| ), | |||
| Container( | |||
| width: double.infinity, | |||
| height: 250, | |||
| margin: EdgeInsets.all(0), | |||
| decoration: BoxDecoration( | |||
| color: Colors.white, | |||
| borderRadius: BorderRadius.only( | |||
| topLeft: Radius.circular(10), | |||
| topRight: Radius.circular(10))), | |||
| child: Column( | |||
| children: <Widget>[ | |||
| widget.title == null || widget.title == '' | |||
| ? Container() | |||
| : Container( | |||
| height: 44, | |||
| child: Row( | |||
| children: <Widget>[ | |||
| FlatButton( | |||
| child: Text('取消'), | |||
| onPressed: () { | |||
| Navigator.pop(context); | |||
| }, | |||
| ), | |||
| Expanded( | |||
| child: Center( | |||
| child: Text( | |||
| widget.title, | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Colors.black.withAlpha(180)), | |||
| ), | |||
| ), | |||
| ), | |||
| FlatButton( | |||
| child: Text( | |||
| '完成', | |||
| style: TextStyle( | |||
| color: HexColor.fromHex('#E52425')), | |||
| ), | |||
| onPressed: () { | |||
| Navigator.pop(context, _dateTime); | |||
| }, | |||
| ), | |||
| ], | |||
| )), | |||
| Expanded( | |||
| child: _createContent(context), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| onTap: () { | |||
| Navigator.pop(context); | |||
| }, | |||
| ), | |||
| ); | |||
| } | |||
| Widget _createContent(BuildContext context) { | |||
| return DatePickerWidget( | |||
| initialDateTime: _dateTime, | |||
| onChange: (dataTime, list) { | |||
| _dateTime = dataTime; | |||
| }, | |||
| pickerTheme: DateTimePickerTheme( | |||
| pickerHeight: 180, | |||
| title: Container(), | |||
| ), | |||
| ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,128 @@ | |||
| import 'package:flutter/cupertino.dart'; | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:zhiying_comm/zhiying_comm.dart'; | |||
| class ActionListAlert extends StatefulWidget { | |||
| final String title; | |||
| final List<String> actions; | |||
| final TextStyle normalStyle; | |||
| final TextStyle selectedStyle; | |||
| const ActionListAlert( | |||
| {Key key, this.title, this.actions, this.normalStyle, this.selectedStyle}) | |||
| : super(key: key); | |||
| @override | |||
| State<StatefulWidget> createState() => _ActionListAlert(); | |||
| } | |||
| class _ActionListAlert extends State<ActionListAlert> { | |||
| int _currentIndex = 0; | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| backgroundColor: Colors.transparent, | |||
| body: GestureDetector( | |||
| child: Column( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Container(), | |||
| ), | |||
| Container( | |||
| width: double.infinity, | |||
| height: 250, | |||
| margin: EdgeInsets.all(0), | |||
| decoration: BoxDecoration( | |||
| color: Colors.white, | |||
| borderRadius: BorderRadius.only( | |||
| topLeft: Radius.circular(10), | |||
| topRight: Radius.circular(10))), | |||
| child: Column( | |||
| children: <Widget>[ | |||
| widget.title == null || widget.title == '' | |||
| ? Container() | |||
| : Container( | |||
| height: 44, | |||
| child: Row( | |||
| children: <Widget>[ | |||
| FlatButton( | |||
| child: Text('取消'), | |||
| onPressed: () { | |||
| Navigator.pop(context); | |||
| }, | |||
| ), | |||
| Expanded( | |||
| child: Center( | |||
| child: Text( | |||
| widget.title, | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Colors.black.withAlpha(180)), | |||
| ), | |||
| ), | |||
| ), | |||
| FlatButton( | |||
| child: Text( | |||
| '完成', | |||
| style: TextStyle( | |||
| color: HexColor.fromHex('#E52425')), | |||
| ), | |||
| onPressed: () { | |||
| Navigator.pop(context, _currentIndex); | |||
| }, | |||
| ), | |||
| ], | |||
| )), | |||
| Expanded( | |||
| child: _createContent(context), | |||
| ) | |||
| ], | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| onTap: () { | |||
| Navigator.pop(context); | |||
| }, | |||
| ), | |||
| ); | |||
| } | |||
| Widget _createContent(BuildContext context) { | |||
| List<Widget> widgets = List<Widget>(); | |||
| TextStyle normalStyle = widget.normalStyle ?? | |||
| TextStyle(fontSize: 12, color: HexColor.fromHex('#7f7f7f')); | |||
| TextStyle selectedStyle = widget.selectedStyle ?? | |||
| TextStyle(fontSize: 14, color: HexColor.fromHex('#E52425')); | |||
| for (int index = 0; index < widget.actions.length; index++) { | |||
| int i = index; | |||
| widgets.add(Column( | |||
| children: <Widget>[ | |||
| Container( | |||
| // color: HexColor.random(), | |||
| height: 40, | |||
| child: Center( | |||
| child: Text( | |||
| widget.actions[index], | |||
| style: i == _currentIndex ? selectedStyle : normalStyle, | |||
| ), | |||
| ), | |||
| ) | |||
| ], | |||
| )); | |||
| } | |||
| return CupertinoPicker( | |||
| backgroundColor: Colors.white, | |||
| children: widgets, | |||
| itemExtent: 40, | |||
| onSelectedItemChanged: (int index) { | |||
| setState(() { | |||
| _currentIndex = index; | |||
| }); | |||
| }, | |||
| ); | |||
| } | |||
| } | |||
| @@ -0,0 +1,125 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:zhiying_comm/zhiying_comm.dart'; | |||
| class ActionSelectedAlert extends StatelessWidget { | |||
| final String title; | |||
| final List<String> actions; | |||
| const ActionSelectedAlert({Key key, this.title, this.actions}) | |||
| : super(key: key); | |||
| @override | |||
| Widget build(BuildContext context) { | |||
| return Scaffold( | |||
| backgroundColor: Colors.transparent, | |||
| body: GestureDetector( | |||
| child: Container( | |||
| width: double.infinity, | |||
| // height: double.infinity, | |||
| color: Colors.transparent, | |||
| child: Container( | |||
| width: double.infinity, | |||
| // height: double.infinity, | |||
| // color: Colors.red, | |||
| child: Column( | |||
| children: <Widget>[ | |||
| Expanded( | |||
| child: Container(), | |||
| ), | |||
| Container( | |||
| width: double.infinity, | |||
| margin: EdgeInsets.all(0), | |||
| decoration: BoxDecoration( | |||
| color: Colors.white, | |||
| borderRadius: BorderRadius.only( | |||
| topLeft: Radius.circular(10), | |||
| topRight: Radius.circular(10))), | |||
| child: Column( | |||
| children: <Widget>[ | |||
| title == null || title == '' | |||
| ? Container() | |||
| : Container( | |||
| height: 44, | |||
| child: Center( | |||
| child: Text( | |||
| title, | |||
| style: TextStyle( | |||
| fontSize: 13, | |||
| color: Colors.black.withAlpha(180)), | |||
| ), | |||
| ), | |||
| ), | |||
| title == null || title == '' || actions.length == 0 | |||
| ? Container() | |||
| : Container( | |||
| width: double.infinity, | |||
| height: 0.5, | |||
| color: HexColor.fromHex('#F2F2F2'), | |||
| ), | |||
| _createContent(context), | |||
| Container( | |||
| width: double.infinity, | |||
| height: 4, | |||
| color: HexColor.fromHex('#F2F2F2'), | |||
| ), | |||
| SafeArea( | |||
| child: Container( | |||
| width: double.infinity, | |||
| margin: EdgeInsets.all(0), | |||
| color: Colors.white, | |||
| height: 56, | |||
| child: Center( | |||
| child: Text( | |||
| '取消', | |||
| style: TextStyle( | |||
| fontSize: 17, color: Colors.black), | |||
| ), | |||
| ), | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| ), | |||
| ], | |||
| ), | |||
| )), | |||
| onTap: () { | |||
| Navigator.pop(context); | |||
| }, | |||
| ), | |||
| ); | |||
| } | |||
| Widget _createContent(BuildContext context) { | |||
| List<Widget> widgets = List<Widget>(); | |||
| for (int index = 0; index < actions.length; index++) { | |||
| int i = index; | |||
| widgets.add(Column( | |||
| children: <Widget>[ | |||
| GestureDetector( | |||
| child: Container( | |||
| color: Colors.transparent, | |||
| height: 54, | |||
| child: Center( | |||
| child: Text( | |||
| actions[index], | |||
| style: TextStyle(fontSize: 17, color: Colors.black), | |||
| ), | |||
| ), | |||
| ), | |||
| onTap: () { | |||
| print(i); | |||
| Navigator.pop(context, i); | |||
| }, | |||
| ), | |||
| Container( | |||
| width: double.infinity, | |||
| height: 0.5, | |||
| color: HexColor.fromHex('#F2F2F2'), | |||
| ) | |||
| ], | |||
| )); | |||
| } | |||
| return Column(children: widgets); | |||
| } | |||
| } | |||
| @@ -11,11 +11,16 @@ dependencies: | |||
| flutter: | |||
| sdk: flutter | |||
| flutter_swiper : ^1.1.6 | |||
| flutter_swiper: ^1.1.6 | |||
| bloc: ^4.0.0 | |||
| event_bus: ^1.1.1 | |||
| pull_to_refresh: ^1.6.1 | |||
| flutter_cupertino_date_picker: ^1.0.26+2 | |||
| image_picker: ^0.6.7+3 | |||
| image_cropper: | |||
| git: | |||
| url: 'http://192.168.0.138:3000/FnuoOS_Flutter_Components/Image_Cropper.git' | |||
| ref: '1.2.3+1' | |||
| dev_dependencies: | |||
| flutter_test: | |||
| @@ -58,10 +63,14 @@ flutter: | |||
| # list giving the asset and other descriptors for the font. For | |||
| # example: | |||
| fonts: | |||
| - family: Din | |||
| - family: Din-Bold | |||
| fonts: | |||
| - asset: assets/fonts/DIN-Bold.otf | |||
| - family: Din-Medium | |||
| fonts: | |||
| - asset: assets/fonts/DIN-Medium.otf | |||
| - family: Din | |||
| fonts: | |||
| - asset: assets/fonts/DIN-Regular.otf | |||
| # | |||