mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-03-19 05:19:47 +08:00
Page navigation routing
This commit is contained in:
@@ -80,6 +80,10 @@ class ProxyVpnThread(
|
||||
} catch (e: Exception) {
|
||||
val errorMessage = (e.message ?: e.toString())
|
||||
Log.e(TAG, errorMessage, e)
|
||||
if (!vpnReadChannel.isOpen) {
|
||||
Log.i(TAG, "VPN read channel closed")
|
||||
running = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ class AppConfiguration {
|
||||
|
||||
if (Platforms.isMobile()) 'pipEnabled': pipEnabled.value,
|
||||
if (Platforms.isMobile()) 'pipIcon': pipIcon.value ? true : null,
|
||||
if (Platforms.isMobile()) 'bottomNavigation': bottomNavigation ? true : null,
|
||||
if (Platforms.isMobile()) 'bottomNavigation': bottomNavigation,
|
||||
|
||||
if (Platforms.isDesktop())
|
||||
"windowSize": windowSize == null ? null : {"width": windowSize?.width, "height": windowSize?.height},
|
||||
|
||||
@@ -35,26 +35,17 @@ import 'package:network_proxy/ui/mobile/widgets/about.dart';
|
||||
|
||||
/// @author wanghongen
|
||||
/// 2024/9/30
|
||||
class MePage extends StatelessWidget {
|
||||
class MePage extends StatefulWidget {
|
||||
final ProxyServer proxyServer;
|
||||
|
||||
const MePage({super.key, required this.proxyServer});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Navigator(
|
||||
initialRoute: '/',
|
||||
onGenerateRoute: (settings) {
|
||||
return MaterialPageRoute(builder: (context) => _MeMenus(proxyServer: proxyServer), settings: settings);
|
||||
},
|
||||
);
|
||||
}
|
||||
State<StatefulWidget> createState() => _MePageState();
|
||||
}
|
||||
|
||||
class _MeMenus extends StatelessWidget {
|
||||
final ProxyServer proxyServer;
|
||||
|
||||
const _MeMenus({required this.proxyServer});
|
||||
class _MePageState extends State<MePage> {
|
||||
late ProxyServer proxyServer = widget.proxyServer;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -66,14 +57,16 @@ class _MeMenus extends StatelessWidget {
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(42),
|
||||
child: AppBar(
|
||||
title: Text(localizations.me, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500)))),
|
||||
title: Text(localizations.me, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w400)),
|
||||
centerTitle: true,
|
||||
)),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.only(top: 5, left: 5),
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
ListTile(
|
||||
title: Text(localizations.httpsProxy),
|
||||
leading: Icon(Icons.https, color: proxyServer.enableSsl ? color : Colors.red),
|
||||
leading: Icon(Icons.https, color: color),
|
||||
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
onTap: () => navigator(context, MobileSslWidget(proxyServer: proxyServer))),
|
||||
const Divider(thickness: 0.35),
|
||||
@@ -145,7 +138,6 @@ class _MeMenus extends StatelessWidget {
|
||||
}
|
||||
|
||||
void navigator(BuildContext context, Widget widget) async {
|
||||
await Navigator.maybePop(context);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (BuildContext context) => widget),
|
||||
|
||||
@@ -46,6 +46,7 @@ import 'package:network_proxy/ui/mobile/widgets/pip.dart';
|
||||
import 'package:network_proxy/utils/ip.dart';
|
||||
import 'package:network_proxy/utils/lang.dart';
|
||||
import 'package:network_proxy/utils/listenable_list.dart';
|
||||
import 'package:network_proxy/utils/navigator.dart';
|
||||
|
||||
///移动端首页
|
||||
///@author wanghongen
|
||||
@@ -123,18 +124,27 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
|
||||
|
||||
int exitTime = 0;
|
||||
|
||||
var requestPageNavigatorKey = GlobalKey<NavigatorState>();
|
||||
var toolboxNavigatorKey = GlobalKey<NavigatorState>();
|
||||
var mePageNavigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var navigationView = [
|
||||
Workspace(proxyServer: proxyServer, appConfiguration: widget.appConfiguration),
|
||||
Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(42),
|
||||
child: AppBar(
|
||||
title: Text(localizations.toolbox, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500)),
|
||||
centerTitle: true)),
|
||||
body: Toolbox(proxyServer: proxyServer)),
|
||||
MePage(proxyServer: proxyServer),
|
||||
NavigatorPage(
|
||||
navigatorKey: requestPageNavigatorKey,
|
||||
child: RequestPage(proxyServer: proxyServer, appConfiguration: widget.appConfiguration)),
|
||||
NavigatorPage(
|
||||
navigatorKey: toolboxNavigatorKey,
|
||||
child: Scaffold(
|
||||
appBar: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(42),
|
||||
child: AppBar(
|
||||
title: Text(localizations.toolbox,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w400)),
|
||||
centerTitle: true)),
|
||||
body: Toolbox(proxyServer: proxyServer))),
|
||||
NavigatorPage(navigatorKey: mePageNavigatorKey, child: MePage(proxyServer: proxyServer)),
|
||||
];
|
||||
|
||||
if (!widget.appConfiguration.bottomNavigation) _selectIndex.value = 0;
|
||||
@@ -146,6 +156,10 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
|
||||
return;
|
||||
}
|
||||
|
||||
if (navigationView[_selectIndex.value].onPopInvoked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DateTime.now().millisecondsSinceEpoch - exitTime > 2000) {
|
||||
exitTime = DateTime.now().millisecondsSinceEpoch;
|
||||
if (mounted) {
|
||||
@@ -162,19 +176,23 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
|
||||
builder: (context, index, child) => Scaffold(
|
||||
body: LazyIndexedStack(index: index, children: navigationView),
|
||||
bottomNavigationBar: widget.appConfiguration.bottomNavigation
|
||||
? SizedBox(
|
||||
height: 72,
|
||||
child: BottomNavigationBar(
|
||||
selectedFontSize: 0,
|
||||
items: [
|
||||
BottomNavigationBarItem(icon: const Icon(Icons.workspaces), label: localizations.requests),
|
||||
BottomNavigationBarItem(icon: const Icon(Icons.construction), label: localizations.toolbox),
|
||||
BottomNavigationBarItem(icon: const Icon(Icons.person), label: localizations.me),
|
||||
],
|
||||
currentIndex: _selectIndex.value,
|
||||
onTap: (index) => _selectIndex.value = index,
|
||||
),
|
||||
)
|
||||
? Container(
|
||||
constraints: const BoxConstraints(maxHeight: 72),
|
||||
child: Theme(
|
||||
data: Theme.of(context).copyWith(splashColor: Colors.transparent),
|
||||
child: BottomNavigationBar(
|
||||
selectedFontSize: 0,
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
icon: const Icon(Icons.workspaces), label: localizations.requests),
|
||||
BottomNavigationBarItem(
|
||||
icon: const Icon(Icons.construction), label: localizations.toolbox),
|
||||
BottomNavigationBarItem(icon: const Icon(Icons.person), label: localizations.me),
|
||||
],
|
||||
currentIndex: _selectIndex.value,
|
||||
onTap: (index) => _selectIndex.value = index,
|
||||
),
|
||||
))
|
||||
: null)));
|
||||
}
|
||||
|
||||
@@ -280,17 +298,17 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
|
||||
}
|
||||
}
|
||||
|
||||
class Workspace extends StatefulWidget {
|
||||
class RequestPage extends StatefulWidget {
|
||||
final ProxyServer proxyServer;
|
||||
final AppConfiguration appConfiguration;
|
||||
|
||||
const Workspace({super.key, required this.proxyServer, required this.appConfiguration});
|
||||
const RequestPage({super.key, required this.proxyServer, required this.appConfiguration});
|
||||
|
||||
@override
|
||||
State<Workspace> createState() => WorkspaceState();
|
||||
State<RequestPage> createState() => RequestPageState();
|
||||
}
|
||||
|
||||
class WorkspaceState extends State<Workspace> {
|
||||
class RequestPageState extends State<RequestPage> {
|
||||
/// 远程连接
|
||||
final ValueNotifier<RemoteModel> desktop = ValueNotifier(RemoteModel(connect: false));
|
||||
|
||||
@@ -428,8 +446,10 @@ class _MobileAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppLocalizations localizations = AppLocalizations.of(context)!;
|
||||
var bottomNavigation = appConfiguration.bottomNavigation;
|
||||
|
||||
return AppBar(
|
||||
leading: bottomNavigation ? const SizedBox() : null,
|
||||
title: MobileSearch(
|
||||
key: MobileApp.searchStateKey, onSearch: (val) => MobileApp.requestStateKey.currentState?.search(val)),
|
||||
actions: [
|
||||
|
||||
@@ -205,7 +205,7 @@ class _FavoriteItemState extends State<_FavoriteItem> {
|
||||
Container(color: Theme.of(context).hoverColor, height: 8),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 50,
|
||||
height: 45,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(localizations.cancel, textAlign: TextAlign.center)),
|
||||
|
||||
@@ -113,15 +113,13 @@ class RequestRowState extends State<RequestRow> {
|
||||
Platform.isIOS ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.only(left: 3, right: 5),
|
||||
onLongPress: menu,
|
||||
onTap: () {
|
||||
NavigatorHelper.push(MaterialPageRoute(
|
||||
settings: const RouteSettings(name: "NetworkTabController"),
|
||||
builder: (context) {
|
||||
return NetworkTabController(
|
||||
proxyServer: widget.proxyServer,
|
||||
httpRequest: request,
|
||||
httpResponse: response,
|
||||
title: Text(localizations.captureDetail, style: const TextStyle(fontSize: 16)));
|
||||
}));
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
|
||||
return NetworkTabController(
|
||||
proxyServer: widget.proxyServer,
|
||||
httpRequest: request,
|
||||
httpResponse: response,
|
||||
title: Text(localizations.captureDetail, style: const TextStyle(fontSize: 16)));
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -171,7 +169,7 @@ class RequestRowState extends State<RequestRow> {
|
||||
child: SizedBox(width: double.infinity, child: Text(localizations.repeat, textAlign: TextAlign.center)),
|
||||
onPressed: () {
|
||||
onRepeat(widget.request);
|
||||
NavigatorHelper.pop();
|
||||
Navigator.maybePop(context);
|
||||
}),
|
||||
const Divider(thickness: 0.5, height: 5),
|
||||
TextButton(
|
||||
@@ -183,10 +181,15 @@ class RequestRowState extends State<RequestRow> {
|
||||
child:
|
||||
SizedBox(width: double.infinity, child: Text(localizations.editRequest, textAlign: TextAlign.center)),
|
||||
onPressed: () {
|
||||
NavigatorHelper.pop();
|
||||
NavigatorHelper.push(MaterialPageRoute(
|
||||
Navigator.maybePop(context);
|
||||
var pageRoute = MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
MobileRequestEditor(request: widget.request, proxyServer: widget.proxyServer)));
|
||||
MobileRequestEditor(request: widget.request, proxyServer: widget.proxyServer));
|
||||
if (mounted) {
|
||||
Navigator.push(context, pageRoute);
|
||||
} else {
|
||||
NavigatorHelper.push(pageRoute);
|
||||
}
|
||||
}),
|
||||
const Divider(thickness: 0.5, height: 5),
|
||||
TextButton(
|
||||
@@ -194,7 +197,7 @@ class RequestRowState extends State<RequestRow> {
|
||||
onPressed: () {
|
||||
FavoriteStorage.addFavorite(widget.request);
|
||||
FlutterToastr.show(localizations.addSuccess, context);
|
||||
NavigatorHelper.pop();
|
||||
Navigator.maybePop(context);
|
||||
}),
|
||||
const Divider(thickness: 0.5, height: 5),
|
||||
TextButton(
|
||||
@@ -202,20 +205,17 @@ class RequestRowState extends State<RequestRow> {
|
||||
onPressed: () {
|
||||
widget.onRemove?.call(request);
|
||||
FlutterToastr.show(localizations.deleteSuccess, context);
|
||||
NavigatorHelper.pop();
|
||||
Navigator.maybePop(context);
|
||||
}),
|
||||
Container(
|
||||
color: Theme.of(context).hoverColor,
|
||||
height: 8,
|
||||
),
|
||||
Container(color: Theme.of(context).hoverColor, height: 8),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 55,
|
||||
height: 45,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(localizations.cancel, textAlign: TextAlign.center)),
|
||||
onPressed: () {
|
||||
NavigatorHelper.pop();
|
||||
Navigator.maybePop(context);
|
||||
},
|
||||
),
|
||||
]);
|
||||
@@ -228,10 +228,15 @@ class RequestRowState extends State<RequestRow> {
|
||||
|
||||
//显示高级重发
|
||||
showCustomRepeat(HttpRequest request) {
|
||||
NavigatorHelper.pop();
|
||||
NavigatorHelper.push(MaterialPageRoute(
|
||||
Navigator.maybePop(context);
|
||||
var pageRoute = MaterialPageRoute(
|
||||
builder: (context) => futureWidget(SharedPreferences.getInstance(),
|
||||
(prefs) => MobileCustomRepeat(onRepeat: () => onRepeat(request), prefs: prefs))));
|
||||
(prefs) => MobileCustomRepeat(onRepeat: () => onRepeat(request), prefs: prefs)));
|
||||
if (mounted) {
|
||||
Navigator.push(context, pageRoute);
|
||||
} else {
|
||||
NavigatorHelper.push(pageRoute);
|
||||
}
|
||||
}
|
||||
|
||||
onRepeat(HttpRequest request) {
|
||||
@@ -249,8 +254,10 @@ class RequestRowState extends State<RequestRow> {
|
||||
child: SizedBox(width: double.infinity, child: Text(title, textAlign: TextAlign.center)),
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(text: callback.call())).then((value) {
|
||||
FlutterToastr.show(localizations.copied, context);
|
||||
NavigatorHelper.pop();
|
||||
if (mounted) {
|
||||
FlutterToastr.show(localizations.copied, context);
|
||||
Navigator.maybePop(context);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ class MobileSearchState extends State<MobileSearch> {
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
border: InputBorder.none,
|
||||
prefixIcon:
|
||||
InkWell(onTap: showSearch, child: Icon(Icons.search, color: _searched ? Colors.green : Colors.blue)),
|
||||
prefixIcon: InkWell(
|
||||
onTap: showSearch, child: Icon(Icons.search, color: _searched ? Colors.green : Colors.blue)),
|
||||
hintText: 'Search')));
|
||||
}
|
||||
|
||||
|
||||
@@ -397,7 +397,7 @@ class _DomainListState extends State<DomainList> {
|
||||
Container(color: Theme.of(context).hoverColor, height: 8),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 50,
|
||||
height: 45,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(localizations.cancel, textAlign: TextAlign.center)),
|
||||
|
||||
@@ -340,7 +340,7 @@ class _RequestRuleListState extends State<RequestRuleList> {
|
||||
Container(color: Theme.of(context).hoverColor, height: 8),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 50,
|
||||
height: 45,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(localizations.cancel, textAlign: TextAlign.center)),
|
||||
|
||||
@@ -668,7 +668,7 @@ class _ScriptListState extends State<ScriptList> {
|
||||
Container(color: Theme.of(context).hoverColor, height: 8),
|
||||
TextButton(
|
||||
child: Container(
|
||||
height: 50,
|
||||
height: 45,
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(localizations.cancel, textAlign: TextAlign.center)),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NavigatorHelper {
|
||||
static final NavigatorHelper _instance = NavigatorHelper._internal();
|
||||
|
||||
//私有构造方法
|
||||
NavigatorHelper._internal();
|
||||
|
||||
@@ -10,10 +12,7 @@ class NavigatorHelper {
|
||||
|
||||
GlobalKey<NavigatorState> get navigatorKey => _navigatorKey;
|
||||
|
||||
BuildContext get context =>
|
||||
NavigatorHelper().navigatorKey.currentState!.context;
|
||||
|
||||
static final NavigatorHelper _instance = NavigatorHelper._internal();
|
||||
BuildContext get context => NavigatorHelper().navigatorKey.currentState!.context;
|
||||
|
||||
//保存单例
|
||||
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
||||
@@ -29,10 +28,39 @@ class NavigatorHelper {
|
||||
}
|
||||
|
||||
//返回上一页
|
||||
static Future<bool> maybePop<T extends Object?>( [ T? result ]) {
|
||||
static Future<bool> maybePop<T extends Object?>([T? result]) {
|
||||
return Navigator.of(NavigatorHelper().context).maybePop<T>(result);
|
||||
}
|
||||
}
|
||||
|
||||
///定义全局的NavigatorHelper对象,页面引入该文件后可以直接使用
|
||||
NavigatorHelper navigatorHelper = NavigatorHelper();
|
||||
|
||||
class NavigatorPage extends StatelessWidget {
|
||||
final GlobalKey navigatorKey;
|
||||
final Widget child;
|
||||
|
||||
const NavigatorPage({super.key, required this.child, required this.navigatorKey});
|
||||
|
||||
bool onPopInvoked() {
|
||||
var context = navigatorKey.currentState?.context;
|
||||
if (context == null) return false;
|
||||
if (Navigator.canPop(context)) {
|
||||
Navigator.maybePop(context);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Navigator(
|
||||
key: navigatorKey,
|
||||
initialRoute: '/',
|
||||
onGenerateRoute: (settings) {
|
||||
return MaterialPageRoute(builder: (context) => child, settings: settings);
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user