refactor(router): 改变了路由方式

从路由配置文件改为了路由表
This commit is contained in:
李东云
2023-03-29 14:47:31 +08:00
parent 5acf390e8a
commit a201fdb91c
6 changed files with 133 additions and 212 deletions

View File

@@ -1,107 +0,0 @@
import 'package:flutter/material.dart';
import 'global.dart';
import 'package:bistro/mine/login.dart';
typedef ACFCallback = Future Function(Map userInfo);
///
/// 登录状态检查
///
class AccessControlFilter extends StatefulWidget {
/// 头部
final AppBar? appBar;
/// 标题
final String? title;
/// 内容组件
final Widget child;
/// 未登录的显示
final Widget? didNotLoginWidget;
const AccessControlFilter({
required Key key,
this.appBar,
this.title,
required this.child,
this.didNotLoginWidget,
}) : super(key: key);
@override
AccessControlFilterState createState() => AccessControlFilterState();
}
class AccessControlFilterState extends State<AccessControlFilter> {
/// 登录状态
final bool _isLogin = false;
@override
void initState() {
super.initState();
_updateUserState();
}
@override
void didUpdateWidget(AccessControlFilter oldWidget) {
super.didUpdateWidget(oldWidget);
_updateUserState();
}
/// 更新用户信息
void _updateUserState({data}) {
// final Map userInfo = data != null ? data : UserInfo().userInfo;
// final bool isLogin = userInfo != null && userInfo.length != 0;
// setState(() {
// _isLogin = isLogin;
// });
}
/// 未登录的显示
Widget? _didNotLoginWidget() {
// 如果传入的未登录情况下显示的组件,则采用传入的
if (widget.didNotLoginWidget != null) return widget.didNotLoginWidget;
// 缺省的未登录情况下的显示
return Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.background,
textStyle: TextStyle(
color: Theme.of(context).colorScheme.primary
)
),
child: const Text('请先登录'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) {
return Login(
successCallback: (Map data) {
_updateUserState(data: data);
printWhenDebug('登录成功');
},
key: widget.key ?? const Key('acf'),
);
},
),
);
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: widget.appBar ??
AppBar(
centerTitle: true,
title: Text(widget.title ?? ""),
),
body: _isLogin ? widget.child : _didNotLoginWidget(),
);
}
}

View File

@@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio_http_cache/dio_http_cache.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@@ -19,9 +19,9 @@ const _themes = <MaterialColor>[
/// 当调试模式打开时打印 /// 当调试模式打开时打印
/// ///
void printWhenDebug(Object object) { void printWhenDebug(Object object) {
if (kDebugMode) { if (kDebugMode) {
print(object); print(object);
} }
} }
/// ///
@@ -36,12 +36,12 @@ class Global {
static SharedPreferences? _prefs; static SharedPreferences? _prefs;
static Dio? dio; static Dio? dio;
static Map profile = {}; static Map profile = {};
/// ///
/// 当前环境 /// 当前环境
/// ///
static const Env env = Env.dev; static const Env env = Env.dev;
/// ///
/// 根域名 /// 根域名
/// ///
@@ -57,11 +57,11 @@ class Global {
static String baseUrl = baseUrlList[env]; static String baseUrl = baseUrlList[env];
// 网络缓存对象 // 网络缓存对象
static DioCacheManager netCache = DioCacheManager( // static DioCacheManager netCache = DioCacheManager(
CacheConfig( // CacheConfig(
baseUrl: baseUrl, // baseUrl: baseUrl,
), // ),
); // );
// 可选的主题列表 // 可选的主题列表
static List<MaterialColor> get themes => _themes; static List<MaterialColor> get themes => _themes;
@@ -70,27 +70,19 @@ class Global {
static bool get isRelease => const bool.fromEnvironment("dart.vm.product"); static bool get isRelease => const bool.fromEnvironment("dart.vm.product");
//初始化全局信息会在APP启动时执行 //初始化全局信息会在APP启动时执行
static Future init() async { static Future init(context) async {
dio = Dio(); dio = Dio();
// 添加拦截器
dio?.interceptors.add(netCache.interceptor);
// 初始化用户信息 // 初始化用户信息
_prefs = await SharedPreferences.getInstance(); _prefs = await SharedPreferences.getInstance();
var profile = _prefs?.getString("user_info"); var profile = _prefs?.getString("user_info");
if (profile != null) { if (profile != null) {
try { try {
if (kDebugMode) { printWhenDebug('开始读取用户信息...');
print('开始读取用户信息...');
}
profile = jsonDecode(profile); profile = jsonDecode(profile);
if (kDebugMode) { printWhenDebug('用户信息读取成功');
print('用户信息读取成功');
}
} catch (e) { } catch (e) {
if (kDebugMode) { printWhenDebug(e);
print(e);
}
} }
} }
} }
@@ -103,7 +95,7 @@ class Global {
} }
/// 读取持久化Profile信息 /// 读取持久化Profile信息
static Future<Map> getProfile() { static Map<String, dynamic> getProfile() {
return jsonDecode(_prefs?.getString("user_info") ?? '{}'); return jsonDecode(_prefs?.getString("user_info") ?? '{}');
} }
} }

View File

@@ -1,28 +1,47 @@
import 'package:bistro/common/global.dart'; import 'package:bistro/common/global.dart';
import 'package:bistro/router/router_table.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
// import 'package:flutter_localizations/flutter_localizations.dart'; // import 'package:flutter_localizations/flutter_localizations.dart';
import 'app.dart'; import 'app.dart';
import 'life.dart'; import 'life.dart';
import 'mine.dart'; import 'mine.dart';
import 'news.dart'; import 'news.dart';
import 'router/router.dart';
void main() { void main() {
// 保证核心已启动
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
//
SystemChrome.setEnabledSystemUIMode( SystemChrome.setEnabledSystemUIMode(
SystemUiMode.edgeToEdge, SystemUiMode.edgeToEdge,
overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top], overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top],
); );
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
runApp(const Bistro()); // 只允许竖屏
SystemChrome.setPreferredOrientations(
[
DeviceOrientation.portraitUp, // 竖屏 Portrait 模式
DeviceOrientation.portraitDown,
// DeviceOrientation.landscapeLeft, // 横屏 Landscape 模式
// DeviceOrientation.landscapeRight,
],
);
// web 使用 pathhistory路由
usePathUrlStrategy();
runApp(Bistro());
} }
class Bistro extends StatelessWidget { class Bistro extends StatelessWidget {
const Bistro({Key? key}) : super(key: key); final GlobalKey<NavigatorState> navigationKey = GlobalKey<NavigatorState>();
Bistro({Key? key}) : super(key: key);
// This widget is the root of your application. // This widget is the root of your application.
@override @override
@@ -33,37 +52,32 @@ class Bistro extends StatelessWidget {
fontFamily: "SongTiHeavy", fontFamily: "SongTiHeavy",
primaryColor: const Color(0xFFD56937), primaryColor: const Color(0xFFD56937),
primaryColorDark: const Color(0xFFD56937), primaryColorDark: const Color(0xFFD56937),
scaffoldBackgroundColor: const Color(0xFF939D99), // appBarTheme: const AppBarTheme(color: Color(0xff384444)),
appBarTheme: const AppBarTheme(color: Color(0xff384444)),
navigationBarTheme: const NavigationBarThemeData( navigationBarTheme: const NavigationBarThemeData(
surfaceTintColor: Color(0xffd56937), indicatorColor: Color(0xFFD56937),
backgroundColor:Color(0xff2a2a22), labelTextStyle: MaterialStatePropertyAll(
indicatorColor: Color(0x00000000), TextStyle(
labelTextStyle: MaterialStatePropertyAll(TextStyle( // color: Color(0xffd56937),
color: Color(0xffd56937), ),
)), ),
), ),
colorScheme: const ColorScheme.dark( colorScheme: const ColorScheme.dark(
primary: Color(0xFFD56937), primary: Color(0xFFD56937),
secondary: Color(0xFFC8C2B4), secondary: Color(0xFFC8C2B4),
background: Color(0xff384444), tertiary: Color(0xff384444),
background: Color(0xff2a2a22),
), ),
useMaterial3: true, useMaterial3: true,
), ),
themeMode: ThemeMode.system,
home: const BistroFrame( home: const BistroFrame(
title: '小酒馆', title: '小酒馆',
), ),
// 国际化
// localizationsDelegates: [
// GlobalMaterialLocalizations.delegate,
// GlobalWidgetsLocalizations.delegate,
// ],
// supportedLocales: const [
// Locale('zh', 'CN'),
// ],
// locale: const Locale('zh'),
// 路由 // 路由
routes: router, // routes: RouterTable.routeTables,
navigatorKey: navigationKey,
onGenerateRoute: RouterTable.onGenerateRoute,
initialRoute: RouterTable.homePath,
); );
} }
} }
@@ -79,31 +93,29 @@ class BistroFrame extends StatefulWidget {
class BistroFrameState extends State<BistroFrame> { class BistroFrameState extends State<BistroFrame> {
late Widget _body; late Widget _body;
int _index = 3; late int _index = 2;
final List<int> loginRequired = [3];
static const List<Map<String, dynamic>> _iconList = [ static const List<Map<String, dynamic>> _iconList = [
{ {
"title": "满席", "title": "满席",
"icon": Icons.storefront_outlined, "icon": Icons.storefront_outlined,
"display": true, "selectedIcon": Icons.storefront_rounded,
}, },
{ {
"title": "道听", "title": "道听",
"icon": Icons.forum_outlined, "icon": Icons.forum_outlined,
"display": true, "selectedIcon": Icons.forum_rounded,
},
{
"display": false,
}, },
{ {
"title": "途说", "title": "途说",
"icon": Icons.supervisor_account_outlined, "icon": Icons.supervisor_account_outlined,
"display": true, "selectedIcon": Icons.supervisor_account_rounded,
}, },
{ {
"title": "在下", "title": "在下",
"icon": Icons.person_outline, "icon": Icons.person_outline,
"display": true, "selectedIcon": Icons.person_rounded,
}, },
]; ];
@@ -113,6 +125,7 @@ class BistroFrameState extends State<BistroFrame> {
super.initState(); super.initState();
initialization(); initialization();
Global.init(context);
} }
void initData() { void initData() {
@@ -121,7 +134,6 @@ class BistroFrameState extends State<BistroFrame> {
children: const <Widget>[ children: const <Widget>[
App(), App(),
News(), News(),
News(),
Life(), Life(),
Mine(), Mine(),
], ],
@@ -140,8 +152,8 @@ class BistroFrameState extends State<BistroFrame> {
// print('ready in 2...'); // print('ready in 2...');
// } // }
// await Future.delayed(const Duration(seconds: 1)); // await Future.delayed(const Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1)); // await Future.delayed(const Duration(seconds: 1));
printWhenDebug('go!'); // printWhenDebug('go!');
FlutterNativeSplash.remove(); FlutterNativeSplash.remove();
} }
@@ -149,25 +161,20 @@ class BistroFrameState extends State<BistroFrame> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
initData(); initData();
List<Widget> bottomNavigationBarData = []; List<NavigationDestination> bottomNavigationBarData = [];
for (var i = 0; i < 5; i++) { for (var i = 0; i < 4; i++) {
Widget itemWidget = bottomAppBarItem(index: i); NavigationDestination itemWidget = bottomAppBarItem(index: i);
bottomNavigationBarData.add(itemWidget); bottomNavigationBarData.add(itemWidget);
} }
return Scaffold( return Scaffold(
body: _body, appBar: AppBar(
bottomNavigationBar: NavigationBar( title: Text(_iconList[_index]['title']),
selectedIndex: _index, systemOverlayStyle: const SystemUiOverlayStyle(
destinations: bottomNavigationBarData, statusBarColor: Colors.transparent, //设置为透明
// backgroundColor: Theme.of(context).colorScheme.primary, ),
onDestinationSelected: (index) => {
setState(() {
_index = index;
})
},
labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
), ),
body: _body,
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
enableFeedback: true, enableFeedback: true,
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.background,
@@ -177,40 +184,34 @@ class BistroFrameState extends State<BistroFrame> {
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
), ),
), ),
floatingActionButtonLocation: bottomNavigationBar: NavigationBar(
FloatingActionButtonLocation.miniCenterDocked, selectedIndex: _index,
destinations: bottomNavigationBarData,
onDestinationSelected: (int index) {
setState(() {
_index = index;
});
loginRequired.forEach((index) {
if (_index == index) {
Navigator.of(context).pushNamed(RouterTable.loginPath);
}
});
},
),
); );
} }
Widget bottomAppBarItem({ NavigationDestination bottomAppBarItem({
required int index, // 序列 required int index, // 序列
}) { }) {
Map<String, dynamic> item = _iconList[index]; Map<String, dynamic> item = _iconList[index];
//设置默认未选中的状态 NavigationDestination child = NavigationDestination(
// TextStyle style = TextStyle( icon: Icon(item['icon']),
// fontSize: size, label: item["title"],
// color: color, selectedIcon: Icon(item['selectedIcon']),
// ); );
bool isShow = item["display"];
Widget child;
if (!isShow) {
child = Container();
} else {
child = NavigationDestination(
icon: Icon(
item['icon'],
color: Theme.of(context).colorScheme.secondary,
),
label: item["title"],
selectedIcon: Icon(
item['icon'],
color: Theme.of(context).primaryColor,
),
);
}
return child; return child;
} }

View File

@@ -1,5 +0,0 @@
import 'package:bistro/app.dart';
var router = {
'/app': (context) => const App(), //应用页
};

View File

@@ -0,0 +1,40 @@
import 'package:bistro/login.dart';
import 'package:flutter/material.dart';
import '../life.dart';
class RouterTable {
// static String splashPath = 'splash';
static String loginPath = 'login';
static String homePath = '/';
// static String notFoundPath = '404';
static Map<String, WidgetBuilder> routeTables = {
//404页面
// notFoundPath: (context) => NotFound(),
//启动页
// splashPath: (context) => Splash(),
//登录
loginPath: (context) => const Login(),
//首页
homePath: (context) => const Life(),
};
///路由拦截
static Route onGenerateRoute<T extends Object>(RouteSettings settings) {
return MaterialPageRoute<T>(
settings: settings,
builder: (context) {
String name = settings.name!;
// if (routeTables[name] == null) {
// name = notFoundPath;
// }
Widget widget = routeTables[name]!(context);
return widget;
},
);
}
}

View File

@@ -13,7 +13,7 @@ import 'package:bistro/main.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(const Bistro()); await tester.pumpWidget(Bistro());
// Verify that our counter starts at 0. // Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);