mobile:add scroll bar to request list

This commit is contained in:
wanghongenpin
2024-08-23 13:30:05 +08:00
parent 982521f58d
commit 462e92aa7d
5 changed files with 101 additions and 72 deletions

View File

@@ -131,16 +131,18 @@ class _DesktopHomePagePageState extends State<DesktopHomePage> implements EventL
'1. iOS 通知栏显示VPN状态\n'
'2. iOS修复停止长时间切换后台再开启抓包无网络问题\n'
'3. 桌面端保存调整左右面板比例;\n'
'4. 修复请求重发和脚本导致URL错误\n'
'5. 修复脚本二进制body转换问题\n'
'6. 修复请求编辑中文路径编码问题;\n'
'4. 手机端请求列表增加滚动条\n'
'5. 修复请求重发和脚本导致URL错误\n'
'6. 修复脚本二进制body转换问题;\n'
'7. 修复请求编辑中文路径编码问题;\n'
: 'TipsBy default, HTTPS packet capture will not be enabled. Please install the certificate before enabling HTTPS packet capture。\n'
'Click HTTPS Capture packets(Lock icon)Choose to install the root certificate and follow the prompts to proceed。\n\n'
'1. iOS notification bar displays VPN status\n'
'2. iOS fix: Stop switching to the background for a long time and then start packet capture without network problem\n'
'3. Desktop: save the left and right panel ratio\n'
'4. fix request repeat & script change url wrong\n'
'5. fix script binary body convert\n'
'4. MobileAdd a scrollbar to the request list\n'
'5. fix request repeat & script change url wrong\n'
'6. fix script binary body convert\n'
'',
style: const TextStyle(fontSize: 14)));
});

View File

@@ -170,7 +170,7 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
child: Scaffold(
floatingActionButton: PictureInPictureIcon(proxyServer),
body: Scaffold(
appBar: appBar(),
appBar: PreferredSize(preferredSize: const Size.fromHeight(42), child: appBar()),
drawer: DrawerWidget(proxyServer: proxyServer, container: container),
floatingActionButton: _launchActionButton(),
body: ValueListenableBuilder(
@@ -226,15 +226,19 @@ class MobileHomeState extends State<MobileHomePage> implements EventListener, Li
? '提示默认不会开启HTTPS抓包请安装证书后再开启HTTPS抓包。\n\n'
'1. iOS 通知栏显示VPN状态\n'
'2. iOS修复停止长时间切换后台再开启抓包无网络问题\n'
'3. 修复请求重发和脚本导致URL错误\n'
'4. 修复脚本二进制body转换问题\n'
'5. 修复请求编辑中文路径编码问题\n'
'3. 桌面端保存调整左右面板比例\n'
'4. 手机端请求列表增加滚动条\n'
'5. 修复请求重发和脚本导致URL错误\n'
'6. 修复脚本二进制body转换问题\n'
'7. 修复请求编辑中文路径编码问题;\n'
: 'TipsBy default, HTTPS packet capture will not be enabled. Please install the certificate before enabling HTTPS packet capture。\n\n'
'Click HTTPS Capture packets(Lock icon)Choose to install the root certificate and follow the prompts to proceed。\n\n'
'1. iOS notification bar displays VPN status\n'
'2. iOS fix: Stop switching to the background for a long time and then start packet capture without network problem\n'
'3. fix request repeat & script change url wrong\n'
'4. fix script binary body convert\n'
'3. Desktop: save the left and right panel ratio\n'
'4. MobileAdd a scrollbar to the request list\n'
'5. fix request repeat & script change url wrong\n'
'6. fix script binary body convert\n'
'';
showAlertDialog(isCN ? '更新内容V1.1.2' : "Update content V1.1.2", content, () {
widget.appConfiguration.upgradeNoticeV12 = false;

View File

@@ -318,38 +318,42 @@ class _HistoryRecordState extends State<HistoryRecord> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: ValueListenableBuilder(
valueListenable: searchEnabled,
builder: (BuildContext context, bool value, Widget? child) {
return value
? MobileSearch(onSearch: (val) => requestStateKey.currentState?.search(val), showSearch: true)
: Text(localizations.historyRecordTitle(widget.history.requestLength, widget.history.name),
style: const TextStyle(fontSize: 16));
}),
actions: [
PopupMenuButton(
offset: const Offset(0, 30),
icon: const Icon(Icons.more_vert_outlined),
itemBuilder: (BuildContext context) {
return [
PopupMenuItem(
onTap: () => searchEnabled.value = true,
child: IconText(icon: const Icon(Icons.search), text: localizations.search)),
PopupMenuItem(
onTap: export, child: IconText(icon: const Icon(Icons.share), text: localizations.viewExport)),
PopupMenuItem(
onTap: () async {
HistoryStorage storage = await HistoryStorage.instance;
var requests = (await storage.getRequests(widget.history)).reversed;
//重发所有请求
_repeatAllRequests(requests.toList(), widget.proxyServer, context: mounted ? context : null);
},
child: IconText(icon: const Icon(Icons.repeat), text: localizations.repeatAllRequests)),
];
}),
],
),
appBar: PreferredSize(
preferredSize: const Size.fromHeight(38),
child: AppBar(
title: ValueListenableBuilder(
valueListenable: searchEnabled,
builder: (BuildContext context, bool value, Widget? child) {
return value
? MobileSearch(onSearch: (val) => requestStateKey.currentState?.search(val), showSearch: true)
: Text(localizations.historyRecordTitle(widget.history.requestLength, widget.history.name),
style: const TextStyle(fontSize: 16));
}),
actions: [
PopupMenuButton(
offset: const Offset(0, 30),
icon: const Icon(Icons.more_vert_outlined),
itemBuilder: (BuildContext context) {
return [
PopupMenuItem(
onTap: () => searchEnabled.value = true,
child: IconText(icon: const Icon(Icons.search), text: localizations.search)),
PopupMenuItem(
onTap: export,
child: IconText(icon: const Icon(Icons.share), text: localizations.viewExport)),
PopupMenuItem(
onTap: () async {
HistoryStorage storage = await HistoryStorage.instance;
var requests = (await storage.getRequests(widget.history)).reversed;
//重发所有请求
_repeatAllRequests(requests.toList(), widget.proxyServer,
context: mounted ? context : null);
},
child: IconText(icon: const Icon(Icons.repeat), text: localizations.repeatAllRequests)),
];
}),
],
)),
body: futureWidget(
loading: true,
HistoryStorage.instance.then((storage) => storage.getRequests(widget.history)),

View File

@@ -145,6 +145,9 @@ class RequestSequence extends StatefulWidget {
}
class RequestSequenceState extends State<RequestSequence> with AutomaticKeepAliveClientMixin {
// Define a ScrollController
final ScrollController _scrollController = ScrollController();
///请求和对应的row的映射
Map<HttpRequest, GlobalKey<RequestRowState>> indexes = HashMap();
@@ -174,6 +177,7 @@ class RequestSequenceState extends State<RequestSequence> with AutomaticKeepAliv
@override
dispose() {
KeywordHighlight.keywordsController.removeListener(highlightListener);
_scrollController.dispose();
super.dispose();
}
@@ -253,26 +257,30 @@ class RequestSequenceState extends State<RequestSequence> with AutomaticKeepAliv
Widget build(BuildContext context) {
super.build(context);
return ListView.separated(
cacheExtent: 1000,
separatorBuilder: (context, index) => Divider(thickness: 0.2, height: 0, color: Theme.of(context).dividerColor),
itemCount: view.length,
itemBuilder: (context, index) {
GlobalKey<RequestRowState> key = GlobalKey();
indexes[view.elementAt(index)] = key;
return RequestRow(
index: view.length - index,
key: key,
request: view.elementAt(index),
proxyServer: widget.proxyServer,
displayDomain: widget.displayDomain,
onRemove: (request) {
setState(() {
view.remove(request);
});
widget.onRemove?.call([request]);
});
});
return Scrollbar(
controller: _scrollController,
child: ListView.separated(
controller: _scrollController,
cacheExtent: 1000,
separatorBuilder: (context, index) =>
Divider(thickness: 0.2, height: 0, color: Theme.of(context).dividerColor),
itemCount: view.length,
itemBuilder: (context, index) {
GlobalKey<RequestRowState> key = GlobalKey();
indexes[view.elementAt(index)] = key;
return RequestRow(
index: view.length - index,
key: key,
request: view.elementAt(index),
proxyServer: widget.proxyServer,
displayDomain: widget.displayDomain,
onRemove: (request) {
setState(() {
view.remove(request);
});
widget.onRemove?.call([request]);
});
}));
}
}
@@ -291,6 +299,8 @@ class DomainList extends StatefulWidget {
}
class DomainListState extends State<DomainList> with AutomaticKeepAliveClientMixin {
final ScrollController _scrollController = ScrollController();
GlobalKey<RequestSequenceState> requestSequenceKey = GlobalKey<RequestSequenceState>();
late Configuration configuration;
@@ -403,15 +413,24 @@ class DomainListState extends State<DomainList> with AutomaticKeepAliveClientMix
@override
bool get wantKeepAlive => true;
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
return ListView.separated(
padding: EdgeInsets.zero,
separatorBuilder: (context, index) =>
Divider(thickness: 0.2, height: 0.5, color: Theme.of(context).dividerColor),
itemCount: view.length,
itemBuilder: (ctx, index) => title(index));
return Scrollbar(
controller: _scrollController,
child: ListView.separated(
controller: _scrollController,
padding: EdgeInsets.zero,
separatorBuilder: (context, index) =>
Divider(thickness: 0.2, height: 0.5, color: Theme.of(context).dividerColor),
itemCount: view.length,
itemBuilder: (ctx, index) => title(index)));
}
Widget title(int index) {

View File

@@ -16,9 +16,9 @@ dependencies:
crypto: ^3.0.3
cupertino_icons: ^1.0.2
basic_utils: ^5.7.0
logger: ^2.0.1
date_format: ^2.0.7
window_manager: ^0.4.0
logger: ^2.4.0
date_format: ^2.0.9
window_manager: ^0.4.2
desktop_multi_window:
git:
url: https://gitee.com/wanghongenpin/flutter-plugins.git