phase3(critical-path): store + main + routes + nav components null-safe

- store/state + reducers: nullable AppState fields & reducer types
- main.dart: localeResolutionCallback Locale?, settings.name? guard
- routes.dart: fluro 2.0.5 HandlerFunc (BuildContext?) + params['x']!
- navigationbar/breadcrumbs/bottom_nav/text_link: nullable optional params/fields
This commit is contained in:
2026-07-24 13:37:04 +08:00
parent cef00db911
commit ae4c4046c3
6 changed files with 106 additions and 102 deletions

View File

@@ -2,7 +2,7 @@
import 'package:flutter/material.dart';
class BottomNav extends StatefulWidget {
const BottomNav({Key key}) : super(key: key);
const BottomNav({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() {

View File

@@ -7,10 +7,10 @@ import '../../routes.dart';
import 'navigationbar.dart';
class BreadCrumbs extends StatelessWidget {
final List<BreadCrumb> breadCrumbs;
final List<BreadCrumb>? breadCrumbs;
final bool hasBack;
final OnBackPress onBackPress;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key, this.onBackPress}) : super(key: key);
final OnBackPress? onBackPress;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key? key, this.onBackPress}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -49,11 +49,11 @@ class BreadCrumbs extends StatelessWidget {
));
}
if (breadCrumbs != null) {
for (int i = 0; i < breadCrumbs.length; i++) {
BreadCrumb breadCrumb = breadCrumbs[i];
for (int i = 0; i < breadCrumbs!.length; i++) {
BreadCrumb breadCrumb = breadCrumbs![i];
if (breadCrumb.text == null && breadCrumb.item != null) {
if (breadCrumb.onTap == null) {
widgets.add(breadCrumb.item);
widgets.add(breadCrumb.item!);
} else {
widgets.add(MouseRegion(
cursor: SystemMouseCursors.click,
@@ -186,9 +186,9 @@ class BreadCrumbs extends StatelessWidget {
class BreadCrumb {
final String text;
final String route;
final IconData icon;
final Widget item;
final Function onTap;
final IconData? icon;
final Widget? item;
final GestureTapCallback? onTap;
BreadCrumb(this.text, this.route, {this.icon, this.item, this.onTap});
}

View File

@@ -9,17 +9,17 @@ import 'breadcrumbs.dart';
typedef OnBackPress();
class MiniNavigationBar extends StatefulWidget implements PreferredSizeWidget {
final Key key;
final Key? key;
final String title;
final bool back;
final bool toHome;
final bool showMe;
final List<BreadCrumb> breadCrumbs;
final double breadCrumbHeight;
final Widget shoppingCart;
final List<BreadCrumb>? breadCrumbs;
final double? breadCrumbHeight;
final Widget? shoppingCart;
MiniNavigationBar({Key key, PreferredSizeWidget bottom, String title,
bool back, bool toHome, bool showMe, this.breadCrumbs,
MiniNavigationBar({Key? key, PreferredSizeWidget? bottom, String? title,
bool? back, bool? toHome, bool? showMe, this.breadCrumbs,
this.breadCrumbHeight, this.shoppingCart})
: key = key,
preferredSize = breadCrumbHeight != null ? Size.fromHeight(kToolbarHeight + breadCrumbHeight) :
@@ -47,9 +47,9 @@ class MiniNavigationBarState extends State<MiniNavigationBar> {
mobile: MobileNavigationBar(title: widget.title, back: widget.back,
toHome: widget.toHome, showMe: widget.showMe,),
tablet: DesktopNavigationBar(hasBack: widget.back,
breadCrumbs: widget.breadCrumbs, shoppingCart: widget.shoppingCart,),
breadCrumbs: widget.breadCrumbs ?? [], shoppingCart: widget.shoppingCart ?? const SizedBox.shrink(),),
desktop: DesktopNavigationBar(hasBack: widget.back,
breadCrumbs: widget.breadCrumbs, shoppingCart: widget.shoppingCart,),
breadCrumbs: widget.breadCrumbs ?? [], shoppingCart: widget.shoppingCart ?? const SizedBox.shrink(),),
);
}

View File

@@ -11,22 +11,22 @@ import '../../routes.dart';
class TextLink extends StatelessWidget {
final String title;
final String url;
final Color color;
final Color hoverColor;
final double paddingHorizontal;
final double paddingVertical;
final FontWeight fontWeight;
final bool selected;
final Color? color;
final Color? hoverColor;
final double? paddingHorizontal;
final double? paddingVertical;
final FontWeight? fontWeight;
final bool? selected;
final bool isLink;
final bool replace;
final bool clearStack;
final bool maintainState;
final bool rootNavigator;
final TransitionType transition;
final TransitionType? transition;
final bool closeDrawer;
final bool isEmail;
final bool isPhone;
final double fontSize;
final double? fontSize;
final bool isAddress;
final TextOverflow overflow;
final int maxLines;
@@ -38,19 +38,19 @@ class TextLink extends StatelessWidget {
this.paddingVertical,
this.fontWeight,
this.selected,
bool isLink,
bool replace,
bool clearStack,
bool maintainState,
bool rootNavigator,
bool? isLink,
bool? replace,
bool? clearStack,
bool? maintainState,
bool? rootNavigator,
this.transition,
bool closeDrawer,
bool isEmail,
bool isPhone,
double fontSize,
bool isAddress,
TextOverflow overflow,
int maxLines,
bool? closeDrawer,
bool? isEmail,
bool? isPhone,
double? fontSize,
bool? isAddress,
TextOverflow? overflow,
int? maxLines,
}) :
isLink = isLink ?? false,
replace = replace ?? false,
@@ -60,7 +60,7 @@ class TextLink extends StatelessWidget {
closeDrawer = closeDrawer ?? false,
isEmail = isEmail ?? false,
isPhone = isPhone ?? false,
fontSize = fontSize ?? null,
fontSize = fontSize,
isAddress = isAddress ?? false,
overflow = overflow ?? TextOverflow.ellipsis,
maxLines = maxLines ?? 1;
@@ -101,7 +101,7 @@ class TextLink extends StatelessWidget {
},
),
decoration: BoxDecoration(
border: (selected != null && selected) ? Border(
border: (selected == true) ? Border(
bottom: BorderSide(
color: color ?? Colors.blue,
width: 3.0,
@@ -110,7 +110,7 @@ class TextLink extends StatelessWidget {
),
),
onTap: () async {
if (selected == null || !selected) {
if (selected != true) {
if (isEmail) {
Utils.openEmail(url);
} else if (isPhone) {