Skip to content

Commit 29f0e44

Browse files
author
code3-dev
committed
add per-app tunnel
1 parent e03b8f8 commit 29f0e44

24 files changed

Lines changed: 534 additions & 197 deletions

‎android/app/build.gradle.kts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ android {
2626
// For more information, see: https://flutter.dev/to/review-gradle-config.
2727
minSdk = flutter.minSdkVersion
2828
targetSdk = flutter.targetSdkVersion
29-
versionCode = 17
30-
versionName = "2.5.0"
29+
versionCode = 18
30+
versionName = "2.5.5"
3131
}
3232

3333
buildTypes {

‎lib/models/app_update.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class AppUpdate {
66
final String messText;
77

88
// Current app version - manually set
9-
static const String currentAppVersion = '2.5.0';
9+
static const String currentAppVersion = '2.5.5';
1010

1111
AppUpdate({required this.version, required this.url, required this.messText});
1212

‎lib/providers/v2ray_provider.dart‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
215215
configIds.where((id) => !existingConfigIds.contains(id)).toList();
216216

217217
if (missingConfigIds.isNotEmpty) {
218-
print(
218+
debugPrint(
219219
'Warning: Found ${missingConfigIds.length} missing configs for subscription ${subscription.name}',
220220
);
221221
// Update the subscription to remove missing config IDs
@@ -517,7 +517,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
517517
} catch (e) {
518518
// Record failed subscription
519519
failedSubscriptions.add(subscription.name);
520-
print('Error updating subscription ${subscription.name}: $e');
520+
debugPrint('Error updating subscription ${subscription.name}: $e');
521521
}
522522
}
523523

@@ -779,7 +779,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
779779
notifyListeners();
780780
})
781781
.catchError((e) {
782-
print('Error saving configs after notification disconnect: $e');
782+
debugPrint('Error saving configs after notification disconnect: $e');
783783
notifyListeners();
784784
});
785785
}
@@ -808,7 +808,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
808808
final isActuallyConnected = await _v2rayService.isActuallyConnected();
809809
final activeConfig = _v2rayService.activeConfig;
810810

811-
print(
811+
debugPrint(
812812
'Fetching notification status - Connected: $isActuallyConnected, Active config: ${activeConfig?.remark}',
813813
);
814814

@@ -839,11 +839,11 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
839839
if (statusChanged) {
840840
await _v2rayService.saveConfigs(_configs);
841841
notifyListeners();
842-
print('Connection status updated from notification');
842+
debugPrint('Connection status updated from notification');
843843
}
844844
}
845845
} catch (e) {
846-
print('Error fetching notification status: $e');
846+
debugPrint('Error fetching notification status: $e');
847847
// Don't change connection state on errors
848848
}
849849
}
@@ -877,7 +877,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
877877
}
878878
}
879879
} catch (e) {
880-
print('Error checking connection status: $e');
880+
debugPrint('Error checking connection status: $e');
881881
// Don't change connection state on errors
882882
}
883883
}

‎lib/screens/about_screen.dart‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
22
import 'package:url_launcher/url_launcher.dart';
33

44
class AboutScreen extends StatelessWidget {
5-
const AboutScreen({Key? key}) : super(key: key);
5+
const AboutScreen({super.key});
66

77
Future<void> _launchUrl(String url) async {
88
final Uri uri = Uri.parse(url);
@@ -48,7 +48,7 @@ class AboutScreen extends StatelessWidget {
4848

4949
// App Version
5050
const Text(
51-
'Version 2.5.0',
51+
'Version 2.5.5',
5252
style: TextStyle(fontSize: 16, color: Colors.grey),
5353
),
5454

‎lib/screens/blocked_apps_screen.dart‎

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import '../services/v2ray_service.dart';
55
import 'package:flutter/foundation.dart';
66

77
class BlockedAppsScreen extends StatefulWidget {
8-
const BlockedAppsScreen({Key? key}) : super(key: key);
8+
const BlockedAppsScreen({super.key});
99

1010
@override
1111
State<BlockedAppsScreen> createState() => _BlockedAppsScreenState();
@@ -77,18 +77,16 @@ class _BlockedAppsScreenState extends State<BlockedAppsScreen> {
7777
List<AppInfo> appInfoList = [];
7878

7979
// For Android, we expect a list of maps with name and packageName
80-
if (apps is List<dynamic>) {
81-
for (var app in apps) {
82-
if (app is Map<String, dynamic>) {
83-
appInfoList.add(
84-
AppInfo(
85-
name: app['name'] ?? 'Unknown',
86-
packageName: app['packageName'] ?? '',
87-
isSystemApp: app['isSystemApp'] ?? false,
88-
),
89-
);
90-
}
91-
}
80+
final appsList = apps as List<dynamic>? ?? [];
81+
for (var app in appsList) {
82+
final appMap = app as Map<String, dynamic>? ?? {};
83+
appInfoList.add(
84+
AppInfo(
85+
name: appMap['name'] ?? 'Unknown',
86+
packageName: appMap['packageName'] ?? '',
87+
isSystemApp: appMap['isSystemApp'] ?? false,
88+
),
89+
);
9290
}
9391

9492
setState(() {
@@ -196,11 +194,11 @@ class _BlockedAppsScreenState extends State<BlockedAppsScreen> {
196194
decoration: InputDecoration(
197195
hintText: 'Search apps...',
198196
hintStyle: TextStyle(
199-
color: Colors.white.withOpacity(0.5),
197+
color: Colors.white.withValues(alpha: 0.5),
200198
),
201199
prefixIcon: const Icon(Icons.search, color: Colors.white),
202200
filled: true,
203-
fillColor: AppTheme.primaryDark.withOpacity(0.5),
201+
fillColor: AppTheme.primaryDark.withValues(alpha: 0.5),
204202
border: OutlineInputBorder(
205203
borderRadius: BorderRadius.circular(10),
206204
borderSide: BorderSide.none,
@@ -232,7 +230,7 @@ class _BlockedAppsScreenState extends State<BlockedAppsScreen> {
232230
horizontal: 8,
233231
vertical: 4,
234232
),
235-
color: AppTheme.primaryDark.withOpacity(0.8),
233+
color: AppTheme.primaryDark.withValues(alpha: 0.8),
236234
child: ListTile(
237235
leading: CircleAvatar(
238236
backgroundColor: app.isSystemApp
@@ -252,7 +250,7 @@ class _BlockedAppsScreenState extends State<BlockedAppsScreen> {
252250
subtitle: Text(
253251
app.packageName,
254252
style: TextStyle(
255-
color: Colors.white.withOpacity(0.7),
253+
color: Colors.white.withValues(alpha: 0.7),
256254
fontSize: 12,
257255
),
258256
),

‎lib/screens/home_screen.dart‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import '../services/v2ray_service.dart';
1111
import 'subscription_management_screen.dart';
1212

1313
class HomeScreen extends StatefulWidget {
14-
const HomeScreen({Key? key}) : super(key: key);
14+
const HomeScreen({super.key});
1515

1616
@override
1717
State<HomeScreen> createState() => _HomeScreenState();
@@ -273,7 +273,7 @@ class _HomeScreenState extends State<HomeScreen> {
273273
borderRadius: BorderRadius.circular(16),
274274
boxShadow: [
275275
BoxShadow(
276-
color: Colors.black.withOpacity(0.1),
276+
color: Colors.black.withValues(alpha: 0.1),
277277
blurRadius: 10,
278278
offset: const Offset(0, 4),
279279
),

‎lib/screens/host_checker_screen.dart‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import 'dart:async';
44
import '../theme/app_theme.dart';
55

66
class HostCheckerScreen extends StatefulWidget {
7-
const HostCheckerScreen({Key? key}) : super(key: key);
7+
const HostCheckerScreen({super.key});
88

99
@override
1010
State<HostCheckerScreen> createState() => _HostCheckerScreenState();
@@ -245,7 +245,7 @@ class _HostCheckerScreenState extends State<HostCheckerScreen> {
245245
foregroundColor: Colors.white,
246246
padding: const EdgeInsets.symmetric(vertical: 16),
247247
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
248-
disabledBackgroundColor: AppTheme.primaryGreen.withOpacity(0.5),
248+
disabledBackgroundColor: AppTheme.primaryGreen.withValues(alpha: 0.5),
249249
),
250250
child:
251251
_isLoading
@@ -364,8 +364,8 @@ class _HostCheckerScreenState extends State<HostCheckerScreen> {
364364
decoration: BoxDecoration(
365365
color:
366366
isSuccess
367-
? Colors.green.withOpacity(0.1)
368-
: Colors.red.withOpacity(0.1),
367+
? Colors.green.withValues(alpha: 0.1)
368+
: Colors.red.withValues(alpha: 0.1),
369369
borderRadius: BorderRadius.circular(12),
370370
),
371371
child: Icon(

‎lib/screens/ip_info_screen.dart‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import '../providers/v2ray_provider.dart';
66
import '../theme/app_theme.dart';
77

88
class IpInfoScreen extends StatefulWidget {
9-
const IpInfoScreen({Key? key}) : super(key: key);
9+
const IpInfoScreen({super.key});
1010

1111
@override
1212
State<IpInfoScreen> createState() => _IpInfoScreenState();

‎lib/screens/main_navigation_screen.dart‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'tools_screen.dart';
1010
import 'store_screen.dart';
1111

1212
class MainNavigationScreen extends StatefulWidget {
13-
const MainNavigationScreen({Key? key}) : super(key: key);
13+
const MainNavigationScreen({super.key});
1414

1515
@override
1616
State<MainNavigationScreen> createState() => _MainNavigationScreenState();
@@ -107,7 +107,7 @@ class _MainNavigationScreenState extends State<MainNavigationScreen> {
107107
color: AppTheme.primaryDark,
108108
boxShadow: [
109109
BoxShadow(
110-
color: Colors.black.withOpacity(0.2),
110+
color: Colors.black.withValues(alpha: 0.2),
111111
blurRadius: 10,
112112
offset: const Offset(0, -3),
113113
),

‎lib/screens/per_app_tunnel_screen.dart‎

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import '../services/v2ray_service.dart';
55
import 'package:flutter/foundation.dart';
66

77
class PerAppTunnelScreen extends StatefulWidget {
8-
const PerAppTunnelScreen({Key? key}) : super(key: key);
8+
const PerAppTunnelScreen({super.key});
99

1010
@override
1111
State<PerAppTunnelScreen> createState() => _PerAppTunnelScreenState();
@@ -76,18 +76,16 @@ class _PerAppTunnelScreenState extends State<PerAppTunnelScreen> {
7676
// Convert the raw data to AppInfo objects
7777
List<AppInfo> appInfoList = [];
7878

79-
if (apps is List<dynamic>) {
80-
for (var app in apps) {
81-
if (app is Map<String, dynamic>) {
82-
appInfoList.add(
83-
AppInfo(
84-
name: app['name'] ?? 'Unknown',
85-
packageName: app['packageName'] ?? '',
86-
isSystemApp: app['isSystemApp'] ?? false,
87-
),
88-
);
89-
}
90-
}
79+
final appsList = apps as List<dynamic>? ?? [];
80+
for (var app in appsList) {
81+
final appMap = app as Map<String, dynamic>? ?? {};
82+
appInfoList.add(
83+
AppInfo(
84+
name: appMap['name'] ?? 'Unknown',
85+
packageName: appMap['packageName'] ?? '',
86+
isSystemApp: appMap['isSystemApp'] ?? false,
87+
),
88+
);
9189
}
9290

9391
// For "per-app tunnel": selected apps = available - blocked
@@ -219,7 +217,7 @@ class _PerAppTunnelScreenState extends State<PerAppTunnelScreen> {
219217
),
220218
child: Text(
221219
'Select apps to use the VPN tunnel. Unselected apps will be blocked.',
222-
style: TextStyle(color: Colors.white.withOpacity(0.85)),
220+
style: TextStyle(color: Colors.white.withValues(alpha: 0.85)),
223221
),
224222
),
225223
// Search bar
@@ -232,7 +230,7 @@ class _PerAppTunnelScreenState extends State<PerAppTunnelScreen> {
232230
decoration: InputDecoration(
233231
hintText: 'Search apps...',
234232
hintStyle: TextStyle(
235-
color: Colors.white.withOpacity(0.6),
233+
color: Colors.white.withValues(alpha: 0.6),
236234
),
237235
prefixIcon: const Icon(
238236
Icons.search,

0 commit comments

Comments
 (0)