From b04a3fded2ee14dff4412a9fcbf38ba1cf2f1220 Mon Sep 17 00:00:00 2001 From: zhangmeng <494089941@qq.com> Date: Thu, 30 Dec 2021 15:46:54 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/login/china_region_model.dart | 28 ++++ lib/models/login/china_region_model.g.dart | 60 +++++++ lib/models/login/community_model.dart | 20 +++ lib/models/login/community_model.g.dart | 15 ++ lib/models/login/history_login_model.dart | 22 +++ lib/models/login/history_login_model.g.dart | 56 +++++++ lib/models/login/picked_city_model.dart | 42 +++++ lib/models/login/picked_city_model.g.dart | 16 ++ lib/pages/sign/login/login_page.dart | 101 ++++++++++++ lib/pages/sign/login/select_community.dart | 148 +++++++++++++++++ lib/pages/sign/sign_in_page.dart | 14 +- lib/provider/app_provider.dart | 17 +- lib/utils/hive_store.dart | 7 + lib/widget/others/bee_search_text_field.dart | 165 +++++++++++++++++++ lib/widget/picker/bee_city_picker.dart | 159 ++++++++++++++++++ lib/widget/picker/bee_community_picker.dart | 102 ++++++++++++ lib/widget/picker/bee_picker_box.dart | 69 ++++++++ 17 files changed, 1032 insertions(+), 9 deletions(-) create mode 100644 lib/models/login/china_region_model.dart create mode 100644 lib/models/login/china_region_model.g.dart create mode 100644 lib/models/login/community_model.dart create mode 100644 lib/models/login/community_model.g.dart create mode 100644 lib/models/login/history_login_model.dart create mode 100644 lib/models/login/history_login_model.g.dart create mode 100644 lib/models/login/picked_city_model.dart create mode 100644 lib/models/login/picked_city_model.g.dart create mode 100644 lib/pages/sign/login/login_page.dart create mode 100644 lib/pages/sign/login/select_community.dart create mode 100644 lib/widget/others/bee_search_text_field.dart create mode 100644 lib/widget/picker/bee_city_picker.dart create mode 100644 lib/widget/picker/bee_community_picker.dart create mode 100644 lib/widget/picker/bee_picker_box.dart diff --git a/lib/models/login/china_region_model.dart b/lib/models/login/china_region_model.dart new file mode 100644 index 00000000..f92b56eb --- /dev/null +++ b/lib/models/login/china_region_model.dart @@ -0,0 +1,28 @@ +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'china_region_model.g.dart'; + +@JsonSerializable() +@HiveType(typeId: 3) +class ChinaRegionModel { + @HiveField(0) + final int id; + @HiveField(1) + final String name; + @HiveField(2) + final List cityList; + + factory ChinaRegionModel.fromJson(Map json) => + _$ChinaRegionModelFromJson(json); + + const ChinaRegionModel({ + required this.id, + required this.name, + required this.cityList, + }); + + static ChinaRegionModel empty(int parentId) { + return ChinaRegionModel(id: 0, name: '', cityList: []); + } +} diff --git a/lib/models/login/china_region_model.g.dart b/lib/models/login/china_region_model.g.dart new file mode 100644 index 00000000..08dac6d6 --- /dev/null +++ b/lib/models/login/china_region_model.g.dart @@ -0,0 +1,60 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'china_region_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ChinaRegionModelAdapter extends TypeAdapter { + @override + final int typeId = 3; + + @override + ChinaRegionModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return ChinaRegionModel( + id: fields[0] as int, + name: fields[1] as String, + cityList: (fields[2] as List).cast(), + ); + } + + @override + void write(BinaryWriter writer, ChinaRegionModel obj) { + writer + ..writeByte(3) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.name) + ..writeByte(2) + ..write(obj.cityList); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ChinaRegionModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChinaRegionModel _$ChinaRegionModelFromJson(Map json) => + ChinaRegionModel( + id: json['id'] as int, + name: json['name'] as String, + cityList: (json['cityList'] as List) + .map((e) => ChinaRegionModel.fromJson(e as Map)) + .toList(), + ); diff --git a/lib/models/login/community_model.dart b/lib/models/login/community_model.dart new file mode 100644 index 00000000..92d540c7 --- /dev/null +++ b/lib/models/login/community_model.dart @@ -0,0 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'community_model.g.dart'; + +@JsonSerializable() +class CommunityModel { + final int id; + final String name; + final String address; + final String addressDetails; + factory CommunityModel.fromJson(Map json) => + _$CommunityModelFromJson(json); + + const CommunityModel({ + required this.id, + required this.name, + required this.address, + required this.addressDetails, + }); +} diff --git a/lib/models/login/community_model.g.dart b/lib/models/login/community_model.g.dart new file mode 100644 index 00000000..2e34b478 --- /dev/null +++ b/lib/models/login/community_model.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'community_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CommunityModel _$CommunityModelFromJson(Map json) => + CommunityModel( + id: json['id'] as int, + name: json['name'] as String, + address: json['address'] as String, + addressDetails: json['addressDetails'] as String, + ); diff --git a/lib/models/login/history_login_model.dart b/lib/models/login/history_login_model.dart new file mode 100644 index 00000000..dc6b1df8 --- /dev/null +++ b/lib/models/login/history_login_model.dart @@ -0,0 +1,22 @@ +import 'package:aku_new_community/models/login/community_model.dart'; +import 'package:aku_new_community/models/login/picked_city_model.dart'; +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'history_login_model.g.dart'; + +@JsonSerializable() +@HiveType(typeId: 4) +class HistoryLoginModel { + @HiveField(0) + final PickedCityModel cityModel; + @HiveField(1) + final CommunityModel communityModel; + factory HistoryLoginModel.fromJson(Map json) => + _$HistoryLoginModelFromJson(json); + + const HistoryLoginModel({ + required this.cityModel, + required this.communityModel, + }); +} diff --git a/lib/models/login/history_login_model.g.dart b/lib/models/login/history_login_model.g.dart new file mode 100644 index 00000000..37327909 --- /dev/null +++ b/lib/models/login/history_login_model.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'history_login_model.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class HistoryLoginModelAdapter extends TypeAdapter { + @override + final int typeId = 4; + + @override + HistoryLoginModel read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return HistoryLoginModel( + cityModel: fields[0] as PickedCityModel, + communityModel: fields[1] as CommunityModel, + ); + } + + @override + void write(BinaryWriter writer, HistoryLoginModel obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.cityModel) + ..writeByte(1) + ..write(obj.communityModel); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is HistoryLoginModelAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +HistoryLoginModel _$HistoryLoginModelFromJson(Map json) => + HistoryLoginModel( + cityModel: + PickedCityModel.fromJson(json['cityModel'] as Map), + communityModel: CommunityModel.fromJson( + json['communityModel'] as Map), + ); diff --git a/lib/models/login/picked_city_model.dart b/lib/models/login/picked_city_model.dart new file mode 100644 index 00000000..33f23195 --- /dev/null +++ b/lib/models/login/picked_city_model.dart @@ -0,0 +1,42 @@ +import 'package:aku_new_community/utils/hive_store.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import 'china_region_model.dart'; + +part 'picked_city_model.g.dart'; + +@JsonSerializable() +class PickedCityModel { + final ChinaRegionModel province; + final ChinaRegionModel city; + final ChinaRegionModel district; + factory PickedCityModel.fromJson(Map json) => + _$PickedCityModelFromJson(json); + + const PickedCityModel({ + required this.province, + required this.city, + required this.district, + }); + factory PickedCityModel.fromId( + {required int provinceId, required int cityId, required int distrctId}) { + var provinces = + HiveStore.chinaRegionBox!.values.cast().toList(); + final _province = + provinces.firstWhere((element) => element.id == provinceId); + final _city = + _province.cityList.firstWhere((element) => element.id == cityId); + final _district = + _city.cityList.firstWhere((element) => element.id == distrctId); + + return PickedCityModel( + province: _province, + city: _city, + district: _district, + ); + } + + String get address => province.name + city.name + district.name; + + int get id => district.id; +} diff --git a/lib/models/login/picked_city_model.g.dart b/lib/models/login/picked_city_model.g.dart new file mode 100644 index 00000000..c7517c3d --- /dev/null +++ b/lib/models/login/picked_city_model.g.dart @@ -0,0 +1,16 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'picked_city_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +PickedCityModel _$PickedCityModelFromJson(Map json) => + PickedCityModel( + province: + ChinaRegionModel.fromJson(json['province'] as Map), + city: ChinaRegionModel.fromJson(json['city'] as Map), + district: + ChinaRegionModel.fromJson(json['district'] as Map), + ); diff --git a/lib/pages/sign/login/login_page.dart b/lib/pages/sign/login/login_page.dart new file mode 100644 index 00000000..b6075407 --- /dev/null +++ b/lib/pages/sign/login/login_page.dart @@ -0,0 +1,101 @@ +import 'package:aku_new_community/base/base_style.dart'; +import 'package:aku_new_community/pages/sign/login/select_community.dart'; +import 'package:aku_new_community/widget/bee_scaffold.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:velocity_x/velocity_x.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({Key? key}) : super(key: key); + + @override + _LoginPageState createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + @override + Widget build(BuildContext context) { + return BeeScaffold( + title: '', + bgColor: Colors.white, + bodyColor: Colors.white, + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + 44.w.heightBox, + '登录解锁更多功能'.text.size(36.sp).color(ktextPrimary).bold.make(), + 144.w.heightBox, + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + GestureDetector( + onTap: () { + Get.to(() => SelectCommunity()); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + '请先选择小区'.text.size(32.sp).color(Color(0xFF5096F1)).make() + ], + ), + ), + 80.w.heightBox, + '${'1547***93018'}' + .text + .size(36.sp) + .color(ktextPrimary) + .bold + .make(), + 40.w.heightBox, + MaterialButton( + onPressed: () {}, + elevation: 0, + height: 100.w, + minWidth: 686.w, + color: kPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(60.w)), + child: '本机号码一键登录'.text.size(32.sp).black.bold.make(), + ), + 24.w.heightBox, + InkWell( + onTap: () {}, + child: Text( + '其他登录方式', + style: TextStyle( + color: Color(0xFF5096F1), + fontSize: 28.sp, + ), + ), + ) + ], + ), + Spacer(), + RichText( + text: TextSpan( + style: TextStyle( + fontSize: 24.sp, + color: ktextSubColor, + ), + text: '注册/登记即代表同意', + children: [ + WidgetSpan( + child: InkWell( + onTap: () { + //TODO:跳转隐私政策 + }, + child: '《小蜜蜂隐私政策及用户协议》' + .text + .size(24.sp) + .color(Color(0xFF5096F1)) + .make(), + )), + ])), + ], + ), + ), + ); + } +} diff --git a/lib/pages/sign/login/select_community.dart b/lib/pages/sign/login/select_community.dart new file mode 100644 index 00000000..ddd15b82 --- /dev/null +++ b/lib/pages/sign/login/select_community.dart @@ -0,0 +1,148 @@ +import 'package:aku_new_community/models/login/community_model.dart'; +import 'package:aku_new_community/models/login/picked_city_model.dart'; +import 'package:aku_new_community/widget/bee_scaffold.dart'; +import 'package:aku_new_community/widget/picker/bee_city_picker.dart'; +import 'package:aku_new_community/widget/picker/bee_community_picker.dart'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:velocity_x/velocity_x.dart'; + +class SelectCommunity extends StatefulWidget { + const SelectCommunity({ + Key? key, + }) : super(key: key); + + @override + _SelectCommunityState createState() => _SelectCommunityState(); +} + +class _SelectCommunityState extends State { + PickedCityModel? _model; + CommunityModel? _community; + + String get cityName { + if (_model == null) { + return '请选择省、市、县/区'; + } else { + return _model!.province.name + _model!.city.name + _model!.district.name; + } + } + + String get communityName { + if (_community == null) { + return '请选择小区'; + } else { + return _community!.name; + } + } + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return BeeScaffold( + title: '选择登录小区', + body: ListView( + children: [ + GestureDetector( + onTap: () async { + _model = await BeeCityPicker.pick(context); + setState(() {}); + }, + child: Container( + color: Colors.white, + width: double.infinity, + height: 88.w, + padding: EdgeInsets.symmetric(vertical: 24.w, horizontal: 32.w), + child: Row( + children: [ + '选择城市'.text.size(28.sp).black.make(), + Spacer(), + '${cityName}'.text.black.make(), + 32.w.widthBox, + Icon( + CupertinoIcons.right_chevron, + size: 20.w, + ) + ], + ), + ), + ), + GestureDetector( + onTap: () async { + var cancel = BotToast.showLoading(); + List _communities = []; + // var base = await NetUtil().get(API.sarsApi.login.allCommunity); + // if (base.status ?? false) { + // _communities = (base.data as List) + // .map((e) => CommunityModel.fromJson(e)) + // .toList(); + // } + cancel(); + _communities = [ + CommunityModel( + id: 0, + name: '111', + address: 'address', + addressDetails: 'addressDetails'), + CommunityModel( + id: 0, + name: '2222', + address: 'address', + addressDetails: 'addressDetails'), + CommunityModel( + id: 0, + name: '3333', + address: 'address', + addressDetails: 'addressDetails'), + CommunityModel( + id: 0, + name: '444', + address: 'address', + addressDetails: 'addressDetails'), + CommunityModel( + id: 0, + name: '5555', + address: 'address', + addressDetails: 'addressDetails') + ]; + _community = await BeeCommunityPicker.pick(context, _communities); + setState(() {}); + }, + child: Container( + color: Colors.white, + width: double.infinity, + height: 88.w, + padding: EdgeInsets.symmetric(vertical: 24.w, horizontal: 32.w), + child: Row( + children: [ + '选择小区'.text.size(28.sp).black.make(), + Spacer(), + '${communityName}'.text.black.make(), + 32.w.widthBox, + Icon( + CupertinoIcons.right_chevron, + size: 20.w, + ) + ], + ), + ), + ), + Container( + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.w), + child: Column( + children: [], + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/sign/sign_in_page.dart b/lib/pages/sign/sign_in_page.dart index fd96c769..27e1ae3b 100644 --- a/lib/pages/sign/sign_in_page.dart +++ b/lib/pages/sign/sign_in_page.dart @@ -1,9 +1,7 @@ import 'dart:async'; -import 'dart:ui'; import 'package:aku_new_community/base/base_style.dart'; -import 'package:aku_new_community/const/resource.dart'; -import 'package:aku_new_community/extensions/num_ext.dart'; +import 'package:aku_new_community/pages/sign/login/login_page.dart'; import 'package:aku_new_community/pages/sign/sign_func.dart'; import 'package:aku_new_community/pages/sign/sign_up/sign_up_set_nickname_page.dart'; import 'package:aku_new_community/pages/tab_navigator.dart'; @@ -12,18 +10,15 @@ import 'package:aku_new_community/provider/user_provider.dart'; import 'package:aku_new_community/utils/headers.dart'; import 'package:aku_new_community/widget/bee_back_button.dart'; import 'package:aku_new_community/widget/bee_scaffold.dart'; +import 'package:aku_new_community/widget/buttons/bottom_button.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:dio/dio.dart'; -import 'package:flustars/flustars.dart' show TextUtil; import 'package:flustars/flustars.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart' hide Response; import 'package:power_logger/power_logger.dart'; import 'package:provider/provider.dart'; -import 'package:velocity_x/velocity_x.dart'; class SignInPage extends StatefulWidget { SignInPage({Key? key}) : super(key: key); @@ -282,6 +277,11 @@ class _SignInPageState extends State { ], )), ), + bottomNavi: BottomButton( + onPressed: () { + Get.to(() => LoginPage()); + }, + child: 'child'.text.make()), ); } } diff --git a/lib/provider/app_provider.dart b/lib/provider/app_provider.dart index 78db2f51..4340f33a 100644 --- a/lib/provider/app_provider.dart +++ b/lib/provider/app_provider.dart @@ -8,6 +8,7 @@ import 'package:aku_new_community/model/community/hot_topic_model.dart'; import 'package:aku_new_community/model/message/message_center_model.dart'; import 'package:aku_new_community/model/user/adress_model.dart'; import 'package:aku_new_community/model/user/car_parking_model.dart'; +import 'package:aku_new_community/models/login/china_region_model.dart'; import 'package:aku_new_community/models/user/passed_house_list_model.dart'; import 'package:aku_new_community/utils/hive_store.dart'; import 'package:aku_new_community/utils/network/base_model.dart'; @@ -17,7 +18,6 @@ import 'package:amap_flutter_location/amap_location_option.dart'; import 'package:collection/collection.dart' show IterableExtension; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:power_logger/power_logger.dart'; class AppProvider extends ChangeNotifier { @@ -326,7 +326,20 @@ class AppProvider extends ChangeNotifier { }); } } - notifyListeners(); } + + ChinaRegionModel? _cityModel; + + ChinaRegionModel? get cityModel => _cityModel; + + Future updateCityList() async { + var model = await NetUtil().get(API.sarsApi.city.allCity); + if (model.status ?? false) { + _cityModel = ChinaRegionModel.fromJson(model.data); + return true; + } else { + return false; + } + } } diff --git a/lib/utils/hive_store.dart b/lib/utils/hive_store.dart index 76b8d560..a50a50b7 100644 --- a/lib/utils/hive_store.dart +++ b/lib/utils/hive_store.dart @@ -1,4 +1,6 @@ import 'package:aku_new_community/model/user/province_model.dart'; +import 'package:aku_new_community/models/login/china_region_model.dart'; +import 'package:aku_new_community/models/login/history_login_model.dart'; import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart'; @@ -7,6 +9,8 @@ class HiveStore { static Box? _appBox; static Box? get appBox => _appBox; + static Box? _chinaRegionBox; + static Box? get chinaRegionBox => _chinaRegionBox; static Future init() async { if (!kIsWeb) { @@ -15,7 +19,10 @@ class HiveStore { Hive.registerAdapter(ProvinceModelAdapter()); Hive.registerAdapter(CityAdapter()); Hive.registerAdapter(DistrictAdapter()); + Hive.registerAdapter(ChinaRegionModelAdapter()); + Hive.registerAdapter(HistoryLoginModelAdapter()); _appBox = await Hive.openBox('app'); + _chinaRegionBox = await Hive.openBox('chinaRegionBox'); } } } diff --git a/lib/widget/others/bee_search_text_field.dart b/lib/widget/others/bee_search_text_field.dart new file mode 100644 index 00000000..d1d02fd6 --- /dev/null +++ b/lib/widget/others/bee_search_text_field.dart @@ -0,0 +1,165 @@ +import 'package:aku_new_community/base/base_style.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +///TextFiled +class BeeSearchTextField extends StatefulWidget implements PreferredSizeWidget { + BeeSearchTextField({ + Key? key, + this.controller, + this.hintText, + this.onChanged, + this.focusNode, + this.onSubmitted, + this.margin, + this.onPressed, + this.height, + }) : button = false, + super(key: key); + + /// + BeeSearchTextField.button({ + Key? key, + this.controller, + this.hintText, + this.onChanged, + this.focusNode, + this.onSubmitted, + this.margin, + this.onPressed, + this.height, + }) : button = true, + super(key: key); + + ///渲染成按钮 + final bool button; + + ///控制器 + final TextEditingController? controller; + + ///hint Text + final String? hintText; + + ///文字变化回调 + final ValueChanged? onChanged; + + ///完成输入回调 + final ValueChanged? onSubmitted; + + ///焦点 + final FocusNode? focusNode; + + ///margin + final EdgeInsets? margin; + + final VoidCallback? onPressed; + + ///高度 + final double? height; + + @override + _BeeSearchTextFieldState createState() => _BeeSearchTextFieldState(); + + @override + Size get preferredSize => Size.fromHeight(this.height ?? 42.w); +} + +class _BeeSearchTextFieldState extends State { + get _border => OutlineInputBorder( + borderRadius: BorderRadius.circular(21.w), + borderSide: BorderSide( + color: Color(0xFF979797), + width: 1.w, + ), + ); + + _buildButton() { + return Padding( + padding: widget.margin ?? + EdgeInsets.symmetric( + horizontal: 15.w, + vertical: 3.w, + ), + child: MaterialButton( + padding: EdgeInsets.zero, + color: Color(0xFFF8F8F8), + elevation: 0, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(21.w), + side: BorderSide( + color: Color(0xFF979797), + width: 1.w, + ), + ), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(left: 26.w, right: 16.w), + child: Icon( + Icons.search, + size: 32.w, + color: Colors.black, + ), + ), + Expanded( + child: Text( + widget.hintText ?? '', + style: TextStyle( + color: ktextSubColor, + fontSize: 28.sp, + ), + ), + ), + ], + ), + onPressed: widget.onPressed, + ), + ); + } + + @override + Widget build(BuildContext context) { + if (widget.button) return _buildButton(); + return Container( + height: 72.w, + padding: widget.margin ?? + EdgeInsets.symmetric( + horizontal: 30.w, + vertical: 6.w, + ), + child: TextField( + controller: widget.controller, + onChanged: widget.onChanged, + onSubmitted: widget.onSubmitted, + onTap: widget.onPressed, + focusNode: widget.focusNode, + cursorColor: kPrimaryColor, + textInputAction: TextInputAction.search, + decoration: InputDecoration( + fillColor: Color(0xFFF8F8F8), + filled: true, + hintText: widget.hintText, + hintStyle: TextStyle( + color: ktextSubColor, + fontSize: 28.sp, + ), + border: _border, + enabledBorder: _border, + focusedBorder: _border, + focusedErrorBorder: _border, + prefixIcon: Padding( + padding: EdgeInsets.only(left: 26.w, right: 16.w), + child: Icon( + Icons.search, + size: 32.w, + color: Colors.black, + ), + ), + prefixIconConstraints: BoxConstraints(minWidth: 0, minHeight: 0), + contentPadding: EdgeInsets.zero, + ), + ), + ); + } +} diff --git a/lib/widget/picker/bee_city_picker.dart b/lib/widget/picker/bee_city_picker.dart new file mode 100644 index 00000000..ee5a0da4 --- /dev/null +++ b/lib/widget/picker/bee_city_picker.dart @@ -0,0 +1,159 @@ +import 'package:aku_new_community/models/login/china_region_model.dart'; +import 'package:aku_new_community/models/login/picked_city_model.dart'; +import 'package:aku_new_community/utils/hive_store.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'bee_picker_box.dart'; + +class BeeCityPicker extends StatefulWidget { + static Future pick(BuildContext context) async { + return await showModalBottomSheet( + context: context, + builder: (context) { + return BeeCityPicker(); + }, + ); + } + + BeeCityPicker({Key? key}) : super(key: key); + + @override + _BeeCityPickerState createState() => _BeeCityPickerState(); +} + +class _BeeCityPickerState extends State { + List get provinces => + HiveStore.chinaRegionBox!.values.cast().toList(); + + late int _pickedProvinceIndex; + late int _pickedCityIndex; + late int _pickedDistrictIndex; + + ChinaRegionModel get _pickedProvince => provinces[_pickedProvinceIndex]; + + ChinaRegionModel get _pickedCity => cities[_pickedCityIndex]; + + ChinaRegionModel get _pickedDistrict => districts.isEmpty + ? ChinaRegionModel.empty(_pickedCity.id) + : districts[_pickedDistrictIndex]; + + List get cities => _pickedProvince.cityList; + + List get districts => _pickedCity.cityList; + + final FixedExtentScrollController _cityController = + FixedExtentScrollController(); + final FixedExtentScrollController _districtController = + FixedExtentScrollController(); + late PickedCityModel _pickedCityModel; + + void updatePickedCity() { + pickCity(); + setState(() {}); + } + + void pickCity() { + _pickedCityModel = PickedCityModel( + province: _pickedProvince, + city: _pickedCity, + district: _pickedDistrict, + ); + } + + @override + void initState() { + super.initState(); + _pickedProvinceIndex = 0; + _pickedCityIndex = 0; + _pickedDistrictIndex = 0; + pickCity(); + } + + @override + void dispose() { + _cityController.dispose(); + _districtController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BeePickerBox( + onPressed: () { + Navigator.pop(context, _pickedCityModel); + }, + child: Row( + children: [ + Expanded( + child: CupertinoPicker( + itemExtent: 40.w, + magnification: 1.1, + offAxisFraction: -0.6, + looping: true, + onSelectedItemChanged: (index) { + _pickedProvinceIndex = index; + _cityController.jumpToItem(0); + _districtController.jumpToItem(0); + updatePickedCity(); + }, + children: provinces + .map((e) => Center( + child: Padding( + padding: EdgeInsets.only(left: 24.w, right: 8.w), + child: Text(e.name, textAlign: TextAlign.center), + ), + )) + .toList(), + ), + ), + Expanded( + child: CupertinoPicker( + itemExtent: 40.w, + magnification: 1.1, + looping: true, + scrollController: _cityController, + onSelectedItemChanged: (index) { + _pickedCityIndex = index; + _districtController.jumpToItem(0); + updatePickedCity(); + }, + children: cities + .map((e) => Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 14.w), + child: Text(e.name, textAlign: TextAlign.center), + ), + )) + .toList(), + ), + ), + Expanded( + child: CupertinoPicker( + itemExtent: 40.w, + magnification: 1.1, + offAxisFraction: 0.6, + looping: true, + scrollController: _districtController, + onSelectedItemChanged: (index) { + _pickedDistrictIndex = index; + updatePickedCity(); + }, + children: districts.isEmpty + ? [Container()] + : districts + .map((e) => Center( + child: Padding( + padding: EdgeInsets.only(left: 4.w, right: 20.w), + child: Text(e.name, textAlign: TextAlign.center), + ), + )) + .toList(), + ), + ), + ], + ), + ); + } +} diff --git a/lib/widget/picker/bee_community_picker.dart b/lib/widget/picker/bee_community_picker.dart new file mode 100644 index 00000000..13da613d --- /dev/null +++ b/lib/widget/picker/bee_community_picker.dart @@ -0,0 +1,102 @@ +import 'package:aku_new_community/models/login/community_model.dart'; +import 'package:aku_new_community/widget/others/bee_search_text_field.dart'; +import 'package:aku_new_community/widget/picker/bee_picker_box.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class BeeCommunityPicker extends StatefulWidget { + static Future pick( + BuildContext context, List communities) async { + return await showModalBottomSheet( + context: context, + builder: (context) { + return BeeCommunityPicker( + communities: communities, + ); + }, + ); + } + + final List communities; + + const BeeCommunityPicker({Key? key, required this.communities}) + : super(key: key); + + @override + _BeeCommunityPickerState createState() => _BeeCommunityPickerState(); +} + +class _BeeCommunityPickerState extends State { + TextEditingController _searchController = TextEditingController(); + CommunityModel? _pickedCommunity; + List _communities = []; + + List screenList(String text) { + var list = []; + widget.communities.forEach((element) { + if (element.name.contains(text)) { + list.add(element); + } + }); + return list; + } + + @override + void initState() { + _communities = widget.communities; + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BeePickerBox( + title: '选择小区', + confirmString: '确定', + onPressed: () { + Navigator.pop(context, _pickedCommunity); + }, + child: Container( + color: Colors.white, + child: Column( + children: [ + BeeSearchTextField( + controller: _searchController, + hintText: '请输入小区名称搜索', + onChanged: (text) { + _communities = screenList(text); + setState(() {}); + }, + ), + Expanded( + child: CupertinoPicker( + itemExtent: 80.w, + looping: false, + onSelectedItemChanged: (index) { + _pickedCommunity = _communities[index]; + }, + children: _communities.isEmpty + ? [Container()] + : _communities + .map((e) => Center( + child: Padding( + padding: + EdgeInsets.only(left: 8.w, right: 40.w), + child: + Text(e.name, textAlign: TextAlign.center), + ), + )) + .toList(), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/widget/picker/bee_picker_box.dart b/lib/widget/picker/bee_picker_box.dart new file mode 100644 index 00000000..91b10ad9 --- /dev/null +++ b/lib/widget/picker/bee_picker_box.dart @@ -0,0 +1,69 @@ +import 'package:aku_new_community/base/base_style.dart'; +import 'package:aku_new_community/widget/bee_divider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class BeePickerBox extends StatelessWidget { + final VoidCallback? onPressed; + final String confirmString; + final String? title; + final Widget child; + + const BeePickerBox( + {Key? key, + this.onPressed, + this.confirmString = '完成', + this.title, + required this.child}) + : super(key: key); + + _buildButton({ + required String title, + required VoidCallback? onPressed, + }) { + return SizedBox( + // height: 48.w, + child: TextButton( + onPressed: onPressed, + child: Text(title), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Material( + color: kForeGroundColor, + child: SizedBox( + height: 650.w, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 88.w, + child: NavigationToolbar( + leading: _buildButton( + title: '取消', + onPressed: () => Navigator.pop(context), + ), + middle: Text( + title ?? '', + style: TextStyle( + color: ktextPrimary, + fontSize: 28.sp, + ), + ), + trailing: _buildButton( + title: confirmString, + onPressed: onPressed, + ), + ), + ), + BeeDivider.horizontal(), + Expanded(child: child), + ], + ), + ), + ); + } +}