phase3: nullfix field-formal field-nullable handler. 907 -> 872

This commit is contained in:
2026-07-25 18:14:55 +08:00
parent fce670664b
commit c21ccbd54d
38 changed files with 151 additions and 131 deletions

View File

@@ -6,9 +6,9 @@ import '../models/business.dart';
import '../models/product.dart'; import '../models/product.dart';
class AttributeSelection extends StatelessWidget { class AttributeSelection extends StatelessWidget {
final Product product; final Product? product;
final Business business; final Business? business;
final GlobalKey startKey; final GlobalKey? startKey;
const AttributeSelection({Key? key, this.product, this.business, this.startKey}) : super(key: key); const AttributeSelection({Key? key, this.product, this.business, this.startKey}) : super(key: key);

View File

@@ -19,7 +19,7 @@ import '../widgets/mobile/mobile_renew_license.dart';
class BuyService extends StatefulWidget { class BuyService extends StatefulWidget {
final int gid; final int gid;
final String serviceName; final String serviceName;
final String domain; final String? domain;
final int sid; final int sid;
const BuyService(this.gid, this.serviceName, {Key? key, this.domain, this.sid = 0}) : const BuyService(this.gid, this.serviceName, {Key? key, this.domain, this.sid = 0}) :

View File

@@ -12,7 +12,7 @@ import '../widgets/desktop/desktop_contact_us.dart';
import '../widgets/mobile/mobile_contact_us.dart'; import '../widgets/mobile/mobile_contact_us.dart';
class ContactUs extends StatefulWidget { class ContactUs extends StatefulWidget {
final int businessId; final int? businessId;
const ContactUs({this.businessId, Key? key}) : const ContactUs({this.businessId, Key? key}) :
super(key: key); super(key: key);

View File

@@ -8,8 +8,8 @@ import '../widgets/mobile/mobile_new_address.dart';
class NewAddress extends StatelessWidget { class NewAddress extends StatelessWidget {
final Key? key; final Key? key;
final LocatedAddress locatedAddress; final LocatedAddress? locatedAddress;
final int businessId; final int? businessId;
const NewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key); const NewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key);
@override @override

View File

@@ -12,7 +12,7 @@ import '../utils/http_util.dart';
import '../utils/utils.dart'; import '../utils/utils.dart';
class PlainPage extends StatefulWidget { class PlainPage extends StatefulWidget {
final int businessId; final int? businessId;
final String slug; final String slug;
const PlainPage(this.slug, {this.businessId, Key? key}) : const PlainPage(this.slug, {this.businessId, Key? key}) :

View File

@@ -10,8 +10,8 @@ import '../widgets/desktop/desktop_product_detail_page.dart';
import '../widgets/mobile/mobile_product_detail_page.dart'; import '../widgets/mobile/mobile_product_detail_page.dart';
class ProductDetailPage extends StatelessWidget { class ProductDetailPage extends StatelessWidget {
final Business business; final Business? business;
final Product product; final Product? product;
const ProductDetailPage({this.business, this.product, Key? key}) : const ProductDetailPage({this.business, this.product, Key? key}) :
super(key: key); super(key: key);

View File

@@ -13,7 +13,7 @@ import '../widgets/mobile/mobile_reset_password.dart';
class ResetPassword extends StatelessWidget { class ResetPassword extends StatelessWidget {
final String mobile; final String mobile;
final String code; final String? code;
const ResetPassword(this.mobile, {Key? key, this.code}) : super(key: key); const ResetPassword(this.mobile, {Key? key, this.code}) : super(key: key);
@override @override

View File

@@ -13,7 +13,7 @@ import '../widgets/mobile/mobile_set_password.dart';
class SetPassword extends StatelessWidget { class SetPassword extends StatelessWidget {
final String mobile; final String mobile;
final String code; final String? code;
const SetPassword(this.mobile, {Key? key, this.code}) : super(key: key); const SetPassword(this.mobile, {Key? key, this.code}) : super(key: key);
@override @override

View File

@@ -8,7 +8,7 @@ import '../widgets/desktop/shop.dart' as desktop;
import '../widgets/mobile/shop.dart' as mobile; import '../widgets/mobile/shop.dart' as mobile;
class Shop extends StatefulWidget { class Shop extends StatefulWidget {
final int businessId; final int? businessId;
const Shop({this.businessId, Key? key}) : super(key: key); const Shop({this.businessId, Key? key}) : super(key: key);

View File

@@ -2,9 +2,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class IFrameWeb extends StatefulWidget { class IFrameWeb extends StatefulWidget {
final String width; final String? width;
final String height; final String? height;
final String src; final String? src;
const IFrameWeb({this.width, this.height, this.src}); const IFrameWeb({this.width, this.height, this.src});

View File

@@ -23,7 +23,7 @@ import '../../widgets/general/navigationbar.dart';
import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart'; import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
class DesktopBlog extends StatefulWidget { class DesktopBlog extends StatefulWidget {
final int businessId; final int? businessId;
const DesktopBlog({Key? key, this.businessId}) : super(key: key); const DesktopBlog({Key? key, this.businessId}) : super(key: key);
@override @override

View File

@@ -19,7 +19,7 @@ import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart'; import '../../widgets/general/navigationbar.dart';
class DesktopMyAddresses extends StatefulWidget { class DesktopMyAddresses extends StatefulWidget {
final int businessId; final int? businessId;
const DesktopMyAddresses({Key? key, this.businessId}) : super(key: key); const DesktopMyAddresses({Key? key, this.businessId}) : super(key: key);
@override @override
@@ -208,7 +208,7 @@ class DesktopMyAddressesState extends State<DesktopMyAddresses> {
), ),
), ),
Container( Container(
child: widget.businessId > 0 ? IconButton( child: widget.businessId! > 0 ? IconButton(
icon: Icon( icon: Icon(
Icons.check, Icons.check,
color: Colors.grey, color: Colors.grey,

View File

@@ -19,7 +19,7 @@ import '../../widgets/general/double_back_to_close_app_wrapper.dart';
import '../../widgets/general/navigationbar.dart'; import '../../widgets/general/navigationbar.dart';
class DesktopMySupport extends StatefulWidget { class DesktopMySupport extends StatefulWidget {
final int businessId; final int? businessId;
const DesktopMySupport({Key? key, this.businessId}) : super(key: key); const DesktopMySupport({Key? key, this.businessId}) : super(key: key);
@override @override

View File

@@ -15,8 +15,8 @@ import '../../widgets/general/navigationbar.dart';
class DesktopNewAddress extends StatefulWidget { class DesktopNewAddress extends StatefulWidget {
final Key? key; final Key? key;
final LocatedAddress locatedAddress; final LocatedAddress? locatedAddress;
final int businessId; final int? businessId;
const DesktopNewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key); const DesktopNewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key);
@override @override
@@ -377,15 +377,15 @@ class DesktopNewAddressState extends State<DesktopNewAddress> {
super.initState(); super.initState();
setState(() { setState(() {
if (widget.locatedAddress != null) { if (widget.locatedAddress != null) {
if (provinces.contains(widget.locatedAddress.province)) { if (provinces.contains(widget.locatedAddress!.province)) {
_selectedProvince = widget.locatedAddress.province; _selectedProvince = widget.locatedAddress!.province;
} }
cityController.text = widget.locatedAddress.city; cityController.text = widget.locatedAddress!.city;
postalCodeController.text = widget.locatedAddress.postalCode; postalCodeController.text = widget.locatedAddress!.postalCode;
streetLine1Controller.text = (widget.locatedAddress.streetNumber != null streetLine1Controller.text = (widget.locatedAddress!.streetNumber != null
&& widget.locatedAddress.streetNumber!.isNotEmpty && widget.locatedAddress!.streetNumber!.isNotEmpty
? widget.locatedAddress.streetNumber! + ' ' : '') ? widget.locatedAddress!.streetNumber! + ' ' : '')
+ widget.locatedAddress.streetName; + widget.locatedAddress!.streetName;
} else { } else {
_selectedProvince = 'Ontario'; _selectedProvince = 'Ontario';
} }
@@ -399,7 +399,7 @@ class DesktopNewAddressState extends State<DesktopNewAddress> {
if (form.validate()) { if (form.validate()) {
HttpUtil.httpPost('v1/addresses', (response) { HttpUtil.httpPost('v1/addresses', (response) {
if (widget.businessId > 0) { if (widget.businessId! > 0) {
Routes.router.navigateTo(context, '/checkout/${widget.businessId}', replace: true); Routes.router.navigateTo(context, '/checkout/${widget.businessId}', replace: true);
} else { } else {
Routes.router.navigateTo(context, '/my-addresses/${widget.businessId}', replace: true); Routes.router.navigateTo(context, '/my-addresses/${widget.businessId}', replace: true);

View File

@@ -28,7 +28,7 @@ import '../../widgets/general/navigationbar.dart';
class DesktopOrderDetail extends StatefulWidget { class DesktopOrderDetail extends StatefulWidget {
final Key? key; final Key? key;
final int orderId; final int orderId;
final bool fromOrders; final bool? fromOrders;
const DesktopOrderDetail(this.orderId, {this.key, this.fromOrders}); const DesktopOrderDetail(this.orderId, {this.key, this.fromOrders});
@override @override

View File

@@ -13,8 +13,8 @@ import '../../widgets/general/style.dart';
import 'desktop_product_detail_page.dart'; import 'desktop_product_detail_page.dart';
class DesktopProductItem extends StatefulWidget { class DesktopProductItem extends StatefulWidget {
final Product product; final Product? product;
final Business business; final Business? business;
final bool horizontal; final bool horizontal;
DesktopProductItem({this.product, this.business, Key? key, this.horizontal = false}) DesktopProductItem({this.product, this.business, Key? key, this.horizontal = false})
@@ -60,7 +60,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
width: 110.0, width: 110.0,
height: 110.0, height: 110.0,
child: GestureDetector( child: GestureDetector(
child: Util.showImage('${widget.product.imagePath}', child: Util.showImage('${widget.product!.imagePath}',
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
onTap: (){ onTap: (){
@@ -76,7 +76,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
Container( Container(
child: GestureDetector( child: GestureDetector(
child: Text( child: Text(
'${widget.product.name}', '${widget.product!.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -91,7 +91,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
), ),
), ),
Text( Text(
widget.product.description, widget.product!.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -107,17 +107,17 @@ class DesktopProductItemState extends State<DesktopProductItem> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
new Container( new Container(
child: widget.business.showMonthlySold ? child: widget.business!.showMonthlySold ?
Text( Text(
S.of(context).sold_per_month_token(widget.product.monthSales!.toStringAsFixed(0)), S.of(context).sold_per_month_token(widget.product!.monthSales!.toStringAsFixed(0)),
style: new TextStyle( style: new TextStyle(
fontSize: 9.0 fontSize: 9.0
), ),
) : SizedBox.shrink(), ) : SizedBox.shrink(),
), ),
ShowPrice( ShowPrice(
widget.product.price, widget.product!.price,
regularPrice: widget.product.regularPrice, regularPrice: widget.product!.regularPrice,
currencySign: '\$', currencySign: '\$',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -142,7 +142,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
width: 110.0, width: 110.0,
height: 110.0, height: 110.0,
child: GestureDetector( child: GestureDetector(
child: Util.showImage('${widget.product.imagePath}', child: Util.showImage('${widget.product!.imagePath}',
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
onTap: (){ onTap: (){
@@ -158,7 +158,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
Container( Container(
child: GestureDetector( child: GestureDetector(
child: Text( child: Text(
'${widget.product.name}', '${widget.product!.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -174,7 +174,7 @@ class DesktopProductItemState extends State<DesktopProductItem> {
), ),
Container( Container(
child: Text( child: Text(
widget.product.description, widget.product!.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -191,17 +191,17 @@ class DesktopProductItemState extends State<DesktopProductItem> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
new Container( new Container(
child: widget.business.showMonthlySold ? child: widget.business!.showMonthlySold ?
Text( Text(
S.of(context).sold_per_month_token(widget.product.monthSales!.toStringAsFixed(0)), S.of(context).sold_per_month_token(widget.product!.monthSales!.toStringAsFixed(0)),
style: new TextStyle( style: new TextStyle(
fontSize: 9.0 fontSize: 9.0
), ),
) : SizedBox.shrink(), ) : SizedBox.shrink(),
), ),
ShowPrice( ShowPrice(
widget.product.price, widget.product!.price,
regularPrice: widget.product.regularPrice, regularPrice: widget.product!.regularPrice,
currencySign: '\$', currencySign: '\$',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),

View File

@@ -10,7 +10,7 @@ import '../../utils/utils.dart';
class DesktopResetPassword extends StatefulWidget { class DesktopResetPassword extends StatefulWidget {
final String mobile; final String mobile;
final String code; final String? code;
const DesktopResetPassword(this.mobile, {this.code, Key? key}) : const DesktopResetPassword(this.mobile, {this.code, Key? key}) :
super(key: key); super(key: key);

View File

@@ -10,7 +10,7 @@ import '../../utils/utils.dart';
class DesktopSetPassword extends StatefulWidget { class DesktopSetPassword extends StatefulWidget {
final String mobile; final String mobile;
final String code; final String? code;
const DesktopSetPassword(this.mobile, {this.code, Key? key}) : const DesktopSetPassword(this.mobile, {this.code, Key? key}) :
super(key: key); super(key: key);

View File

@@ -9,7 +9,7 @@ import '../../utils/utils.dart';
class DesktopShoppingCartWidget extends StatefulWidget { class DesktopShoppingCartWidget extends StatefulWidget {
final Business business; final Business business;
final Function onTap; final Function? onTap;
DesktopShoppingCartWidget({@required this.business, this.onTap}); DesktopShoppingCartWidget({@required this.business, this.onTap});

View File

@@ -22,7 +22,7 @@ import 'shop_promote.dart';
import 'shopping_cart_widget.dart'; import 'shopping_cart_widget.dart';
class Shop extends StatefulWidget { class Shop extends StatefulWidget {
final int businessId; final int? businessId;
const Shop({Key? key, this.businessId}): super(key: key); const Shop({Key? key, this.businessId}): super(key: key);

View File

@@ -10,7 +10,7 @@ import '../../utils/utils.dart';
class ShoppingCartWidget extends StatefulWidget { class ShoppingCartWidget extends StatefulWidget {
final Business business; final Business business;
final Function onTap; final Function? onTap;
ShoppingCartWidget({@required this.business, this.onTap}); ShoppingCartWidget({@required this.business, this.onTap});

View File

@@ -17,8 +17,8 @@ import '../../store/store.dart';
import '../../utils/utils.dart'; import '../../utils/utils.dart';
class AddRemoveButton extends StatefulWidget { class AddRemoveButton extends StatefulWidget {
final Product product; final Product? product;
final Business business; final Business? business;
final bool addOnly; final bool addOnly;
final int cartLineItemIndex; final int cartLineItemIndex;
final bool addToBasket; final bool addToBasket;
@@ -59,12 +59,12 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (widget.product.leftNum == null) { if (widget.product!.leftNum == null) {
_qty = 0; _qty = 0;
cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business); cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business);
if (cartInfo != null) { if (cartInfo != null) {
for (var i = 0; i < cartInfo.productList!.length; i++) { for (var i = 0; i < cartInfo.productList!.length; i++) {
if (cartInfo.productList![i].product!.id == widget.product.id if (cartInfo.productList![i].product!.id == widget.product!.id
&& cartInfo.productList![i].unitPrice == 0.0) { && cartInfo.productList![i].unitPrice == 0.0) {
_qty = cartInfo.productList![i].quantity!.round(); _qty = cartInfo.productList![i].quantity!.round();
break; break;
@@ -78,7 +78,7 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
), ),
); );
} }
if (widget.product.leftNum! <= 0) { if (widget.product!.leftNum! <= 0) {
return Container( return Container(
padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 8.0, right: 8.0), padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 8.0, right: 8.0),
child: Text( child: Text(
@@ -105,7 +105,7 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business); cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business);
if (cartInfo != null) { if (cartInfo != null) {
for (var i = 0; i < cartInfo.productList!.length; i++) { for (var i = 0; i < cartInfo.productList!.length; i++) {
if (cartInfo.productList![i].product!.id == widget.product.id) { if (cartInfo.productList![i].product!.id == widget.product!.id) {
_qty = cartInfo.productList![i].quantity!.round(); _qty = cartInfo.productList![i].quantity!.round();
break; break;
} }
@@ -198,14 +198,14 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business); cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business);
if (cartInfo != null) { if (cartInfo != null) {
for (var i = 0; i < cartInfo.productList!.length; i++) { for (var i = 0; i < cartInfo.productList!.length; i++) {
if (cartInfo.productList![i].product!.id == widget.product.id) { if (cartInfo.productList![i].product!.id == widget.product!.id) {
_qty = cartInfo.productList![i].quantity!.round(); _qty = cartInfo.productList![i].quantity!.round();
break; break;
} }
} }
} }
if (widget.product.productAttributes != null && if (widget.product!.productAttributes != null &&
widget.product.productAttributes!.length > 0 && widget.cartLineItemIndex == -1) { widget.product!.productAttributes!.length > 0 && widget.cartLineItemIndex == -1) {
return new Row( return new Row(
key: startKey, key: startKey,
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
@@ -312,7 +312,7 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
void _addToCart(BuildContext context) { void _addToCart(BuildContext context) {
if (widget.cartLineItemIndex != -1) { if (widget.cartLineItemIndex != -1) {
if (cartInfo.productList![widget.cartLineItemIndex].quantity! + 1.0 > widget.product.leftNum) { if (cartInfo.productList![widget.cartLineItemIndex].quantity! + 1.0 > widget.product!.leftNum) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: S.of(context).product_insufficient, msg: S.of(context).product_insufficient,
toastLength: Toast.LENGTH_SHORT, toastLength: Toast.LENGTH_SHORT,
@@ -328,7 +328,7 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
eventBus.fire(new OnCartInfoUpdated()); eventBus.fire(new OnCartInfoUpdated());
} }
} else { } else {
if (widget.product.productAttributes!.length > 0) { if (widget.product!.productAttributes!.length > 0) {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute(builder: (context) => MaterialPageRoute(builder: (context) =>
@@ -337,7 +337,7 @@ class AddRemoveButtonState extends State<AddRemoveButton> {
); );
} else { } else {
eventBus.fire(new OnProductWillAddToCart(widget.product, {}, eventBus.fire(new OnProductWillAddToCart(widget.product, {},
widget.product.price, widget.product.description, widget.product!.price, widget.product!.description,
widget.business, buttonKey: startKey)); widget.business, buttonKey: startKey));
} }
} }

View File

@@ -12,7 +12,7 @@ import '../../utils/utils.dart';
class DownloadItem extends StatefulWidget { class DownloadItem extends StatefulWidget {
final dynamic desc; final dynamic desc;
final double width; final double? width;
const DownloadItem(this.desc, {Key? key, this.width}) : super(key: key); const DownloadItem(this.desc, {Key? key, this.width}) : super(key: key);
@override @override
@@ -52,7 +52,7 @@ class DownloadItemState extends State<DownloadItem> {
margin: EdgeInsets.only(right: 16.0), margin: EdgeInsets.only(right: 16.0),
), ),
Container( Container(
width: widget.width != null ? widget.width - iconWidth - buttonWidth - 60 : MediaQuery.of(context).size.width - iconWidth - buttonWidth - 60, width: widget.width != null ? widget.width! - iconWidth - buttonWidth - 60 : MediaQuery.of(context).size.width - iconWidth - buttonWidth - 60,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -28,16 +28,16 @@ class ReadMoreText extends StatefulWidget {
final String data; final String data;
final String trimExpandedText; final String trimExpandedText;
final String trimCollapsedText; final String trimCollapsedText;
final Color colorClickableText; final Color? colorClickableText;
final int trimLength; final int trimLength;
final int trimLines; final int trimLines;
final TrimMode trimMode; final TrimMode trimMode;
final TextStyle style; final TextStyle? style;
final TextAlign textAlign; final TextAlign? textAlign;
final TextDirection textDirection; final TextDirection? textDirection;
final Locale locale; final Locale? locale;
final double textScaleFactor; final double? textScaleFactor;
final String semanticsLabel; final String? semanticsLabel;
@override @override
ReadMoreTextState createState() => ReadMoreTextState(); ReadMoreTextState createState() => ReadMoreTextState();
@@ -58,7 +58,7 @@ class ReadMoreTextState extends State<ReadMoreText> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
TextStyle effectiveTextStyle = widget.style; TextStyle effectiveTextStyle = widget.style;
if (widget.style == null || widget.style.inherit) { if (widget.style == null || widget.style!.inherit) {
effectiveTextStyle = defaultTextStyle.style.merge(widget.style); effectiveTextStyle = defaultTextStyle.style.merge(widget.style);
} }

View File

@@ -3,10 +3,10 @@ import 'package:flutter/material.dart';
class ShowPrice extends StatelessWidget { class ShowPrice extends StatelessWidget {
final double price; final double price;
final double regularPrice; final double? regularPrice;
final double largeFontSize; final double largeFontSize;
final double smallFontSize; final double smallFontSize;
final String currencySign; final String? currencySign;
final Color color; final Color color;
final FontWeight fontWeight; final FontWeight fontWeight;
@@ -65,12 +65,12 @@ class ShowPrice extends StatelessWidget {
), ),
), ),
), ),
regularPrice == null || price.round() >= regularPrice.round() ? regularPrice == null || price.round() >= regularPrice!.round() ?
SizedBox.shrink() : SizedBox.shrink() :
Container( Container(
padding: EdgeInsets.only(top: largeFontSize / 2), padding: EdgeInsets.only(top: largeFontSize / 2),
child: Text( child: Text(
regularPrice.toStringAsFixed(0), regularPrice!.toStringAsFixed(0),
style: TextStyle( style: TextStyle(
color: Colors.black38, color: Colors.black38,
fontSize: smallFontSize, fontSize: smallFontSize,

View File

@@ -30,7 +30,7 @@ class SlidingUpPanel extends StatefulWidget {
/// otherwise, [collapsed] will be displayed overtop /// otherwise, [collapsed] will be displayed overtop
/// of this Widget. If [panel] and [panelBuilder] are both non-null, /// of this Widget. If [panel] and [panelBuilder] are both non-null,
/// [panel] will be used. /// [panel] will be used.
final Widget panel; final Widget? panel;
/// WARNING: This feature is still in beta and is subject to change without /// WARNING: This feature is still in beta and is subject to change without
/// notice. Stability is not gauranteed. Provides a [ScrollController] and /// notice. Stability is not gauranteed. Provides a [ScrollController] and
@@ -38,28 +38,28 @@ class SlidingUpPanel extends StatefulWidget {
/// the panel position with the scroll position. Useful for implementing an /// the panel position with the scroll position. Useful for implementing an
/// infinite scroll behavior. If [panel] and [panelBuilder] are both non-null, /// infinite scroll behavior. If [panel] and [panelBuilder] are both non-null,
/// [panel] will be used. /// [panel] will be used.
final Widget Function(ScrollController sc) panelBuilder; final Widget Function(ScrollController sc)? panelBuilder;
/// The Widget displayed overtop the [panel] when collapsed. /// The Widget displayed overtop the [panel] when collapsed.
/// This fades out as the panel is opened. /// This fades out as the panel is opened.
final Widget collapsed; final Widget? collapsed;
/// The Widget that lies underneath the sliding panel. /// The Widget that lies underneath the sliding panel.
/// This Widget automatically sizes itself /// This Widget automatically sizes itself
/// to fill the screen. /// to fill the screen.
final Widget body; final Widget? body;
/// Optional persistent widget that floats above the [panel] and attaches /// Optional persistent widget that floats above the [panel] and attaches
/// to the top of the [panel]. Content at the top of the panel will be covered /// to the top of the [panel]. Content at the top of the panel will be covered
/// by this widget. Add padding to the bottom of the `panel` to /// by this widget. Add padding to the bottom of the `panel` to
/// avoid coverage. /// avoid coverage.
final Widget header; final Widget? header;
/// Optional persistent widget that floats above the [panel] and /// Optional persistent widget that floats above the [panel] and
/// attaches to the bottom of the [panel]. Content at the bottom of the panel /// attaches to the bottom of the [panel]. Content at the bottom of the panel
/// will be covered by this widget. Add padding to the bottom of the `panel` /// will be covered by this widget. Add padding to the bottom of the `panel`
/// to avoid coverage. /// to avoid coverage.
final Widget footer; final Widget? footer;
/// The height of the sliding panel when fully collapsed. /// The height of the sliding panel when fully collapsed.
final double minHeight; final double minHeight;
@@ -72,13 +72,13 @@ class SlidingUpPanel extends StatefulWidget {
/// and go directly to the open/close position. This value is represented as a /// and go directly to the open/close position. This value is represented as a
/// percentage of the total animation distance ([maxHeight] - [minHeight]), /// percentage of the total animation distance ([maxHeight] - [minHeight]),
/// so it must be between 0.0 and 1.0, exclusive. /// so it must be between 0.0 and 1.0, exclusive.
final double snapPoint; final double? snapPoint;
/// A border to draw around the sliding panel sheet. /// A border to draw around the sliding panel sheet.
final Border border; final Border? border;
/// If non-null, the corners of the sliding panel sheet are rounded by this [BorderRadiusGeometry]. /// If non-null, the corners of the sliding panel sheet are rounded by this [BorderRadiusGeometry].
final BorderRadiusGeometry borderRadius; final BorderRadiusGeometry? borderRadius;
/// A list of shadows cast behind the sliding panel sheet. /// A list of shadows cast behind the sliding panel sheet.
final List<BoxShadow> boxShadow; final List<BoxShadow> boxShadow;
@@ -87,10 +87,10 @@ class SlidingUpPanel extends StatefulWidget {
final Color color; final Color color;
/// The amount to inset the children of the sliding panel sheet. /// The amount to inset the children of the sliding panel sheet.
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry? padding;
/// Empty space surrounding the sliding panel sheet. /// Empty space surrounding the sliding panel sheet.
final EdgeInsetsGeometry margin; final EdgeInsetsGeometry? margin;
/// Set to false to not to render the sheet the [panel] sits upon. /// Set to false to not to render the sheet the [panel] sits upon.
/// This means that only the [body], [collapsed], and the [panel] /// This means that only the [body], [collapsed], and the [panel]
@@ -104,7 +104,7 @@ class SlidingUpPanel extends StatefulWidget {
final bool panelSnapping; final bool panelSnapping;
/// If non-null, this can be used to control the state of the panel. /// If non-null, this can be used to control the state of the panel.
final PanelController controller; final PanelController? controller;
/// If non-null, shows a darkening shadow over the [body] as the panel slides open. /// If non-null, shows a darkening shadow over the [body] as the panel slides open.
final bool backdropEnabled; final bool backdropEnabled;
@@ -125,15 +125,15 @@ class SlidingUpPanel extends StatefulWidget {
/// is called as the panel slides around with the /// is called as the panel slides around with the
/// current position of the panel. The position is a double /// current position of the panel. The position is a double
/// between 0.0 and 1.0 where 0.0 is fully collapsed and 1.0 is fully open. /// between 0.0 and 1.0 where 0.0 is fully collapsed and 1.0 is fully open.
final void Function(double position) onPanelSlide; final void Function(double position)? onPanelSlide;
/// If non-null, this callback is called when the /// If non-null, this callback is called when the
/// panel is fully opened /// panel is fully opened
final VoidCallback onPanelOpened; final VoidCallback? onPanelOpened;
/// If non-null, this callback is called when the panel /// If non-null, this callback is called when the panel
/// is fully collapsed. /// is fully collapsed.
final VoidCallback onPanelClosed; final VoidCallback? onPanelClosed;
/// If non-null and true, the SlidingUpPanel exhibits a /// If non-null and true, the SlidingUpPanel exhibits a
/// parallax effect as the panel slides up. Essentially, /// parallax effect as the panel slides up. Essentially,
@@ -320,8 +320,8 @@ class _SlidingUpPanelState extends State<SlidingUpPanel> with SingleTickerProvid
top: widget.slideDirection == SlideDirection.UP ? 0.0 : null, top: widget.slideDirection == SlideDirection.UP ? 0.0 : null,
bottom: widget.slideDirection == SlideDirection.DOWN ? 0.0 : null, bottom: widget.slideDirection == SlideDirection.DOWN ? 0.0 : null,
width: MediaQuery.of(context).size.width - width: MediaQuery.of(context).size.width -
(widget.margin != null ? widget.margin.horizontal : 0) - (widget.margin != null ? widget.margin!.horizontal : 0) -
(widget.padding != null ? widget.padding.horizontal : 0), (widget.padding != null ? widget.padding!.horizontal : 0),
child: Container( child: Container(
height: widget.maxHeight, height: widget.maxHeight,
child: widget.panel != null child: widget.panel != null
@@ -349,8 +349,8 @@ class _SlidingUpPanelState extends State<SlidingUpPanel> with SingleTickerProvid
top: widget.slideDirection == SlideDirection.UP ? 0.0 : null, top: widget.slideDirection == SlideDirection.UP ? 0.0 : null,
bottom: widget.slideDirection == SlideDirection.DOWN ? 0.0 : null, bottom: widget.slideDirection == SlideDirection.DOWN ? 0.0 : null,
width: MediaQuery.of(context).size.width - width: MediaQuery.of(context).size.width -
(widget.margin != null ? widget.margin.horizontal : 0) - (widget.margin != null ? widget.margin!.horizontal : 0) -
(widget.padding != null ? widget.padding.horizontal : 0), (widget.padding != null ? widget.padding!.horizontal : 0),
child: Container( child: Container(
height: widget.minHeight, height: widget.minHeight,
child: widget.collapsed == null ? Container() : FadeTransition( child: widget.collapsed == null ? Container() : FadeTransition(

View File

@@ -20,7 +20,7 @@ class MobileAttributeSelection extends StatefulWidget {
final Product product; final Product product;
final Business business; final Business business;
final Key? key; final Key? key;
final GlobalKey startKey; final GlobalKey? startKey;
const MobileAttributeSelection({@required this.product, @required this.business, this.key, this.startKey}) const MobileAttributeSelection({@required this.product, @required this.business, this.key, this.startKey})
: super(key: key); : super(key: key);

View File

@@ -17,7 +17,7 @@ import '../../utils/utils.dart';
import '../../widgets/mobile/MobileBottomNav.dart'; import '../../widgets/mobile/MobileBottomNav.dart';
class MobileBlog extends StatefulWidget { class MobileBlog extends StatefulWidget {
final int businessId; final int? businessId;
const MobileBlog({Key? key, this.businessId}) : super(key: key); const MobileBlog({Key? key, this.businessId}) : super(key: key);
@override @override

View File

@@ -16,7 +16,7 @@ import 'package:flutter_wisetronic/widgets/mobile/MobileBottomNav.dart';
import '../../routes.dart'; import '../../routes.dart';
class MobileMyAddresses extends StatefulWidget { class MobileMyAddresses extends StatefulWidget {
final int businessId; final int? businessId;
const MobileMyAddresses({Key? key, this.businessId}) : super(key: key); const MobileMyAddresses({Key? key, this.businessId}) : super(key: key);
@override @override
@@ -162,7 +162,7 @@ class MobileMyAddressesState extends State<MobileMyAddresses> {
), ),
), ),
Container( Container(
child: widget.businessId > 0 ? IconButton( child: widget.businessId! > 0 ? IconButton(
icon: Icon( icon: Icon(
Icons.check, Icons.check,
color: Colors.grey, color: Colors.grey,

View File

@@ -17,7 +17,7 @@ import '../../widgets/general/double_back_to_close_app_wrapper.dart';
import '../../widgets/mobile/MobileBottomNav.dart'; import '../../widgets/mobile/MobileBottomNav.dart';
class MobileMySupport extends StatefulWidget { class MobileMySupport extends StatefulWidget {
final int businessId; final int? businessId;
const MobileMySupport({Key? key, this.businessId}) : super(key: key); const MobileMySupport({Key? key, this.businessId}) : super(key: key);
@override @override

View File

@@ -12,8 +12,8 @@ import '../../utils/http_util.dart';
class MobileNewAddress extends StatefulWidget { class MobileNewAddress extends StatefulWidget {
final Key? key; final Key? key;
final LocatedAddress locatedAddress; final LocatedAddress? locatedAddress;
final int businessId; final int? businessId;
const MobileNewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key); const MobileNewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key);
@override @override
@@ -348,15 +348,15 @@ class MobileNewAddressState extends State<MobileNewAddress> {
super.initState(); super.initState();
setState(() { setState(() {
if (widget.locatedAddress != null) { if (widget.locatedAddress != null) {
if (provinces.contains(widget.locatedAddress.province)) { if (provinces.contains(widget.locatedAddress!.province)) {
_selectedProvince = widget.locatedAddress.province; _selectedProvince = widget.locatedAddress!.province;
} }
cityController.text = widget.locatedAddress.city; cityController.text = widget.locatedAddress!.city;
postalCodeController.text = widget.locatedAddress.postalCode; postalCodeController.text = widget.locatedAddress!.postalCode;
streetLine1Controller.text = (widget.locatedAddress.streetNumber != null streetLine1Controller.text = (widget.locatedAddress!.streetNumber != null
&& widget.locatedAddress.streetNumber!.isNotEmpty && widget.locatedAddress!.streetNumber!.isNotEmpty
? widget.locatedAddress.streetNumber! + ' ' : '') ? widget.locatedAddress!.streetNumber! + ' ' : '')
+ widget.locatedAddress.streetName; + widget.locatedAddress!.streetName;
} else { } else {
_selectedProvince = 'Ontario'; _selectedProvince = 'Ontario';
} }
@@ -370,7 +370,7 @@ class MobileNewAddressState extends State<MobileNewAddress> {
if (form.validate()) { if (form.validate()) {
HttpUtil.httpPost('v1/addresses', (response) { HttpUtil.httpPost('v1/addresses', (response) {
if (widget.businessId > 0) { if (widget.businessId! > 0) {
Routes.router.navigateTo(context, '/checkout/${widget.businessId}', replace: true); Routes.router.navigateTo(context, '/checkout/${widget.businessId}', replace: true);
} else { } else {
Routes.router.navigateTo(context, '/my-addresses/${widget.businessId}', replace: true); Routes.router.navigateTo(context, '/my-addresses/${widget.businessId}', replace: true);

View File

@@ -26,7 +26,7 @@ import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dar
class MobileOrderDetail extends StatefulWidget { class MobileOrderDetail extends StatefulWidget {
final Key? key; final Key? key;
final int orderId; final int orderId;
final bool fromOrders; final bool? fromOrders;
const MobileOrderDetail(this.orderId, {this.key, this.fromOrders}); const MobileOrderDetail(this.orderId, {this.key, this.fromOrders});
@override @override

View File

@@ -12,8 +12,8 @@ import '../../widgets/general/show_price.dart';
import '../../widgets/general/style.dart'; import '../../widgets/general/style.dart';
class MobileProductItem extends StatefulWidget { class MobileProductItem extends StatefulWidget {
final Product product; final Product? product;
final Business business; final Business? business;
MobileProductItem({this.product, this.business, Key? key}) MobileProductItem({this.product, this.business, Key? key})
: super(key: key); : super(key: key);
@@ -49,7 +49,7 @@ class MobileProductItemState extends State<MobileProductItem> {
width: 80.0, width: 80.0,
height: 80.0, height: 80.0,
child: GestureDetector( child: GestureDetector(
child: Util.showImage('${widget.product.imagePath}', child: Util.showImage('${widget.product!.imagePath}',
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
onTap: (){ onTap: (){
@@ -65,7 +65,7 @@ class MobileProductItemState extends State<MobileProductItem> {
Container( Container(
child: GestureDetector( child: GestureDetector(
child: Text( child: Text(
'${widget.product.name}', '${widget.product!.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -80,7 +80,7 @@ class MobileProductItemState extends State<MobileProductItem> {
), ),
), ),
new Text( new Text(
widget.product.description, widget.product!.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis, // overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@@ -96,9 +96,9 @@ class MobileProductItemState extends State<MobileProductItem> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
new Container( new Container(
child: widget.business.showMonthlySold ? child: widget.business!.showMonthlySold ?
Text( Text(
S.of(context).sold_per_month_token(widget.product.monthSales!.toStringAsFixed(0)), S.of(context).sold_per_month_token(widget.product!.monthSales!.toStringAsFixed(0)),
style: new TextStyle( style: new TextStyle(
fontSize: 9.0 fontSize: 9.0
), ),
@@ -110,8 +110,8 @@ class MobileProductItemState extends State<MobileProductItem> {
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
children: <Widget>[ children: <Widget>[
ShowPrice( ShowPrice(
widget.product.price, widget.product!.price,
regularPrice: widget.product.regularPrice, regularPrice: widget.product!.regularPrice,
currencySign: '\$', currencySign: '\$',
), ),
], ],

View File

@@ -10,7 +10,7 @@ import '../../utils/utils.dart';
class MobileResetPassword extends StatefulWidget { class MobileResetPassword extends StatefulWidget {
final String mobile; final String mobile;
final String code; final String? code;
const MobileResetPassword(this.mobile, {this.code, Key? key}) const MobileResetPassword(this.mobile, {this.code, Key? key})
: super(key: key); : super(key: key);

View File

@@ -10,7 +10,7 @@ import '../../utils/utils.dart';
class MobileSetPassword extends StatefulWidget { class MobileSetPassword extends StatefulWidget {
final String mobile; final String mobile;
final String code; final String? code;
const MobileSetPassword(this.mobile, {Key? key, this.code}) : super(key: key); const MobileSetPassword(this.mobile, {Key? key, this.code}) : super(key: key);

View File

@@ -43,7 +43,7 @@ late double screenWidth;
late double screenHeight; late double screenHeight;
class Shop extends StatefulWidget { class Shop extends StatefulWidget {
final int businessId; final int? businessId;
const Shop({Key? key, this.businessId}) : super(key: key); const Shop({Key? key, this.businessId}) : super(key: key);

View File

@@ -17,10 +17,10 @@ typedef OnEmptyCartListener();
typedef OnPanelOpenCloseRequest(); typedef OnPanelOpenCloseRequest();
class ShoppingCartBar extends StatefulWidget { class ShoppingCartBar extends StatefulWidget {
final GlobalKey endKey; final GlobalKey? endKey;
final Business business; final Business business;
final OnEmptyCartListener onEmptyCartListener; final OnEmptyCartListener? onEmptyCartListener;
final OnPanelOpenCloseRequest onPanelOpenCloseRequest; final OnPanelOpenCloseRequest? onPanelOpenCloseRequest;
final bool barAtBottom; final bool barAtBottom;
final bool hasPicture; final bool hasPicture;
ShoppingCartBar({@required this.business, this.endKey, ShoppingCartBar({@required this.business, this.endKey,

View File

@@ -101,6 +101,17 @@ def insert_bang(line, col0, name, kind):
return None return None
return None return None
def make_field_nullable(lines, name):
"""找字段声明 'Type name;' 并在类型后加 '?'。返回 (行索引, 新行) 或 (None,None)。"""
pat = re.compile(r'^(\s+(?:final\s+|const\s+)?(?:static\s+)?)(.+)\s+'+re.escape(name)+r';\s*$')
for i,L in enumerate(lines):
m=pat.match(L)
if not m: continue
mod, typ = m.group(1), m.group(2).rstrip()
if '?' in typ or '=' in L: continue
return i, f"{mod}{typ}? {name};"
return None, None
def insert_late(line): def insert_late(line):
stripped=line.strip() stripped=line.strip()
if not stripped or stripped.startswith('late '): return None if not stripped or stripped.startswith('late '): return None
@@ -147,7 +158,16 @@ def apply_round(errs):
if cls: new=insert_bang(old, col-1, cls[0], cls[1]) if cls: new=insert_bang(old, col-1, cls[0], cls[1])
elif rule=='missing_default_value_for_parameter': elif rule=='missing_default_value_for_parameter':
nm=NAME.search(msg) nm=NAME.search(msg)
if nm: new=insert_nullable_before_name(old, nm.group(1), col-1) if nm:
pname=nm.group(1)
# field-formal this.x ? 则把字段改可空(跨行)
if ('this.'+pname) in old:
fl=get(path)
fi, fnew = make_field_nullable(fl, pname)
if fi is not None and fl[fi]!=fnew:
fl[fi]=fnew; changed+=1
else:
new=insert_nullable_before_name(old, pname, col-1)
elif rule in ('not_initialized_non_nullable_instance_field','not_initialized_non_nullable_variable'): elif rule in ('not_initialized_non_nullable_instance_field','not_initialized_non_nullable_variable'):
new=insert_late(old) new=insert_late(old)
if new and new!=old: if new and new!=old: