mirror of
https://github.com/wanghongenpin/proxypin.git
synced 2026-05-16 15:56:51 +08:00
Merge branch 'refs/heads/main' into develop
This commit is contained in:
@@ -153,6 +153,7 @@ class ProxyVpnService : VpnService(), ProtectSocket {
|
||||
|
||||
val notification: Notification =
|
||||
NotificationCompat.Builder(this, VPN_NOTIFICATION_CHANNEL_ID)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setContentIntent(pendingActivityIntent)
|
||||
.setContentTitle(getString(R.string.vpn_active_notification_title))
|
||||
.setContentText(getString(R.string.vpn_active_notification_content))
|
||||
|
||||
@@ -23,11 +23,14 @@ class AppInfo {
|
||||
//icon
|
||||
Uint8List? icon;
|
||||
|
||||
bool? inValid;
|
||||
|
||||
AppInfo({
|
||||
this.name,
|
||||
this.packageName,
|
||||
this.versionName,
|
||||
this.icon,
|
||||
this.inValid,
|
||||
});
|
||||
|
||||
AppInfo.formJson(Map<dynamic, dynamic> json) {
|
||||
@@ -50,4 +53,18 @@ class AppInfo {
|
||||
String toString() {
|
||||
return toJson().toString();
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) {
|
||||
return true;
|
||||
}
|
||||
if (other is AppInfo) {
|
||||
return packageName == other.packageName;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => packageName.hashCode;
|
||||
}
|
||||
|
||||
@@ -348,25 +348,26 @@ class RequestPageState extends State<RequestPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
floatingActionButton: PictureInPictureIcon(proxyServer),
|
||||
body: Scaffold(
|
||||
appBar: _MobileAppBar(widget.appConfiguration, proxyServer, remoteDevice: remoteDevice),
|
||||
drawer: widget.appConfiguration.bottomNavigation
|
||||
? null
|
||||
: DrawerWidget(proxyServer: proxyServer, container: MobileApp.container),
|
||||
floatingActionButton: _launchActionButton(),
|
||||
body: ValueListenableBuilder(
|
||||
valueListenable: remoteDevice,
|
||||
builder: (context, value, _) {
|
||||
return Column(children: [
|
||||
value.connect ? remoteConnect(value) : const SizedBox(),
|
||||
Expanded(
|
||||
child: RequestListWidget(
|
||||
key: MobileApp.requestStateKey, proxyServer: proxyServer, list: MobileApp.container))
|
||||
]);
|
||||
}),
|
||||
));
|
||||
return Stack(children: [
|
||||
Scaffold(
|
||||
appBar: _MobileAppBar(widget.appConfiguration, proxyServer, remoteDevice: remoteDevice),
|
||||
drawer: widget.appConfiguration.bottomNavigation
|
||||
? null
|
||||
: DrawerWidget(proxyServer: proxyServer, container: MobileApp.container),
|
||||
floatingActionButton: _launchActionButton(),
|
||||
body: ValueListenableBuilder(
|
||||
valueListenable: remoteDevice,
|
||||
builder: (context, value, _) {
|
||||
return Column(children: [
|
||||
value.connect ? remoteConnect(value) : const SizedBox(),
|
||||
Expanded(
|
||||
child: RequestListWidget(
|
||||
key: MobileApp.requestStateKey, proxyServer: proxyServer, list: MobileApp.container))
|
||||
]);
|
||||
}),
|
||||
),
|
||||
PictureInPictureIcon(proxyServer),
|
||||
]);
|
||||
}
|
||||
|
||||
Widget _launchActionButton() {
|
||||
|
||||
@@ -58,6 +58,7 @@ class MobileSearchState extends State<MobileSearch> {
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: TextFormField(
|
||||
controller: _keywordController,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
cursorHeight: 20,
|
||||
keyboardType: TextInputType.url,
|
||||
onTapOutside: (event) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
|
||||
@@ -65,7 +65,7 @@ class _AppWhitelistState extends State<AppWhitelist> {
|
||||
var appWhitelist = <Future<AppInfo>>[];
|
||||
for (var element in configuration.appWhitelist) {
|
||||
appWhitelist.add(InstalledApps.getAppInfo(element).catchError((e) {
|
||||
return AppInfo(name: isCN ? "未知应用" : "Unknown app", packageName: element);
|
||||
return AppInfo(name: isCN ? "未知应用" : "Unknown app", packageName: element, inValid: true);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -75,22 +75,41 @@ class _AppWhitelistState extends State<AppWhitelist> {
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
//添加
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (context) => const InstalledAppsWidget()))
|
||||
.then((value) {
|
||||
if (value != null) {
|
||||
if (configuration.appWhitelist.contains(value)) {
|
||||
return;
|
||||
List<AppInfo> list = await Future.wait(appWhitelist);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
|
||||
return InstalledAppsWidget(addedList: list);
|
||||
})).then((value) {
|
||||
if (value != null) {
|
||||
if (configuration.appWhitelist.contains(value)) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
configuration.appWhitelist.add(value);
|
||||
changed = true;
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
configuration.appWhitelist.add(value);
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
tooltip: isCN ? '清除失效应用' : 'clear invalid apps',
|
||||
onPressed: () async {
|
||||
if (configuration.appWhitelist.isEmpty) return;
|
||||
List<AppInfo> list = await Future.wait(appWhitelist);
|
||||
for (AppInfo appInfo in list) {
|
||||
if (appInfo.inValid == true) {
|
||||
configuration.appWhitelist.remove(appInfo.packageName);
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
changed = true;
|
||||
});
|
||||
},
|
||||
icon: Icon(Icons.cleaning_services_outlined),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -193,7 +212,7 @@ class _AppBlacklistState extends State<AppBlacklist> {
|
||||
var appBlacklist = <Future<AppInfo>>[];
|
||||
for (var element in configuration.appBlacklist ?? []) {
|
||||
appBlacklist.add(InstalledApps.getAppInfo(element).catchError((e) {
|
||||
return AppInfo(name: isCN ? "未知应用" : "Unknown app", packageName: element);
|
||||
return AppInfo(name: isCN ? "未知应用" : "Unknown app", packageName: element, inValid: true);
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -203,23 +222,42 @@ class _AppBlacklistState extends State<AppBlacklist> {
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
onPressed: () async {
|
||||
//添加
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (context) => const InstalledAppsWidget()))
|
||||
.then((value) {
|
||||
if (value != null) {
|
||||
if (configuration.appBlacklist?.contains(value) == true) {
|
||||
return;
|
||||
List<AppInfo> list = await Future.wait(appBlacklist);
|
||||
if (context.mounted) {
|
||||
Navigator.of(context)
|
||||
.push(MaterialPageRoute(builder: (context) => InstalledAppsWidget(addedList: list)))
|
||||
.then((value) {
|
||||
if (value != null) {
|
||||
if (configuration.appBlacklist?.contains(value) == true) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
configuration.appBlacklist ??= [];
|
||||
configuration.appBlacklist?.add(value);
|
||||
changed = true;
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
configuration.appBlacklist ??= [];
|
||||
configuration.appBlacklist?.add(value);
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
tooltip: isCN ? '清除失效应用' : 'clear invalid apps',
|
||||
onPressed: () async {
|
||||
if (configuration.appBlacklist?.isEmpty == true) return;
|
||||
List<AppInfo> list = await Future.wait(appBlacklist);
|
||||
for (AppInfo appInfo in list) {
|
||||
if (appInfo.inValid == true) {
|
||||
configuration.appBlacklist?.remove(appInfo.packageName);
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
changed = true;
|
||||
});
|
||||
},
|
||||
icon: Icon(Icons.cleaning_services_outlined),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -267,7 +305,12 @@ class _AppBlacklistState extends State<AppBlacklist> {
|
||||
|
||||
///已安装的app列表
|
||||
class InstalledAppsWidget extends StatefulWidget {
|
||||
const InstalledAppsWidget({super.key});
|
||||
const InstalledAppsWidget({
|
||||
super.key,
|
||||
required this.addedList,
|
||||
});
|
||||
|
||||
final List<AppInfo> addedList;
|
||||
|
||||
@override
|
||||
State<InstalledAppsWidget> createState() => _InstalledAppsWidgetState();
|
||||
@@ -306,6 +349,7 @@ class _InstalledAppsWidgetState extends State<InstalledAppsWidget> {
|
||||
builder: (BuildContext context, AsyncSnapshot<List<AppInfo>> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
List<AppInfo> appInfoList = snapshot.data!;
|
||||
appInfoList = appInfoList.toSet().difference(widget.addedList.toSet()).toList();
|
||||
if (keyword != null && keyword!.trim().isNotEmpty) {
|
||||
appInfoList = appInfoList
|
||||
.where((element) =>
|
||||
|
||||
@@ -183,7 +183,7 @@ class RequestBlockAddDialog extends StatelessWidget {
|
||||
SwitchWidget(title: localizations.enable, value: item.enabled, onChanged: (val) => enabled = val),
|
||||
const SizedBox(height: 10),
|
||||
TextFormField(
|
||||
initialValue: item.url.fixAutoLines(),
|
||||
initialValue: item.url,
|
||||
maxLines: 3,
|
||||
minLines: 1,
|
||||
decoration: const InputDecoration(
|
||||
|
||||
@@ -94,6 +94,9 @@ class _PictureInPictureState extends State<PictureInPictureIcon> {
|
||||
static double xPosition = -1;
|
||||
static double yPosition = -1;
|
||||
static Size? size;
|
||||
late final double _top;
|
||||
late final double _right;
|
||||
late final double _bottom;
|
||||
|
||||
AppLocalizations get localizations => AppLocalizations.of(context)!;
|
||||
|
||||
@@ -117,40 +120,41 @@ class _PictureInPictureState extends State<PictureInPictureIcon> {
|
||||
}
|
||||
|
||||
if (xPosition == -1) {
|
||||
xPosition = size!.width * 0.9;
|
||||
xPosition = size!.width - 48;
|
||||
yPosition = size!.height * 0.35;
|
||||
_top = MediaQuery.of(context).padding.top;
|
||||
_right = xPosition;
|
||||
_bottom = size!.height - 48 - (AppConfiguration.current?.bottomNavigation == false ? 0 : 56);
|
||||
}
|
||||
|
||||
return Stack(children: [
|
||||
Positioned(
|
||||
top: yPosition,
|
||||
left: xPosition,
|
||||
child: GestureDetector(
|
||||
onPanUpdate: (tapInfo) {
|
||||
if (xPosition + tapInfo.delta.dx < 0) return;
|
||||
if (yPosition + tapInfo.delta.dy < 0) return;
|
||||
return Positioned(
|
||||
top: yPosition,
|
||||
left: xPosition,
|
||||
child: GestureDetector(
|
||||
onPanUpdate: (tapInfo) {
|
||||
// if (xPosition + tapInfo.delta.dx < 0) return;
|
||||
// if (yPosition + tapInfo.delta.dy < 0) return;
|
||||
|
||||
setState(() {
|
||||
xPosition += tapInfo.delta.dx;
|
||||
yPosition += tapInfo.delta.dy;
|
||||
});
|
||||
},
|
||||
child: IconButton(
|
||||
tooltip: localizations.windowMode,
|
||||
onPressed: () async {
|
||||
var configuration = widget.proxyServer.configuration;
|
||||
List<String>? appList = configuration.appWhitelistEnabled ? configuration.appWhitelist : [];
|
||||
List<String>? disallowApps;
|
||||
if (appList.isEmpty) {
|
||||
disallowApps = configuration.appBlacklist ?? [];
|
||||
}
|
||||
setState(() {
|
||||
xPosition = (xPosition + tapInfo.delta.dx).clamp(0, _right);
|
||||
yPosition = (yPosition + tapInfo.delta.dy).clamp(_top, _bottom);
|
||||
});
|
||||
},
|
||||
child: IconButton(
|
||||
tooltip: localizations.windowMode,
|
||||
onPressed: () async {
|
||||
var configuration = widget.proxyServer.configuration;
|
||||
List<String>? appList = configuration.appWhitelistEnabled ? configuration.appWhitelist : [];
|
||||
List<String>? disallowApps;
|
||||
if (appList.isEmpty) {
|
||||
disallowApps = configuration.appBlacklist ?? [];
|
||||
}
|
||||
|
||||
PictureInPicture.enterPictureInPictureMode(
|
||||
Platform.isAndroid ? await localIp() : "127.0.0.1", widget.proxyServer.port,
|
||||
appList: appList, disallowApps: disallowApps);
|
||||
},
|
||||
icon: const Icon(Icons.picture_in_picture_alt))),
|
||||
)
|
||||
]);
|
||||
PictureInPicture.enterPictureInPictureMode(
|
||||
Platform.isAndroid ? await localIp() : "127.0.0.1", widget.proxyServer.port,
|
||||
appList: appList, disallowApps: disallowApps);
|
||||
},
|
||||
icon: const Icon(Icons.picture_in_picture_alt))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user